xref: /csrg-svn/sbin/mountd/mountd.c (revision 53214)
138460Smckusick /*
238460Smckusick  * Copyright (c) 1989 The Regents of the University of California.
338460Smckusick  * All rights reserved.
438460Smckusick  *
538460Smckusick  * This code is derived from software contributed to Berkeley by
651667Smckusick  * Herb Hasler and Rick Macklem at The University of Guelph.
738460Smckusick  *
842703Sbostic  * %sccs.include.redist.c%
938460Smckusick  */
1038460Smckusick 
1138460Smckusick #ifndef lint
1238460Smckusick char copyright[] =
1338460Smckusick "@(#) Copyright (c) 1989 Regents of the University of California.\n\
1438460Smckusick  All rights reserved.\n";
1538460Smckusick #endif not lint
1638460Smckusick 
1738460Smckusick #ifndef lint
18*53214Smckusick static char sccsid[] = "@(#)mountd.c	5.22 (Berkeley) 04/20/92";
1938460Smckusick #endif not lint
2038460Smckusick 
2151667Smckusick #include <pwd.h>
2251667Smckusick #include <grp.h>
2351667Smckusick #include <unistd.h>
2451667Smckusick #include <stdlib.h>
2538460Smckusick #include <sys/param.h>
2638460Smckusick #include <sys/ioctl.h>
2738460Smckusick #include <sys/stat.h>
2839681Smckusick #include <sys/file.h>
2951667Smckusick #include <sys/ucred.h>
3038460Smckusick #include <sys/mount.h>
3138460Smckusick #include <sys/socket.h>
3238460Smckusick #include <sys/errno.h>
3342038Sbostic #include <sys/signal.h>
3442038Sbostic #include <stdio.h>
3542038Sbostic #include <string.h>
3652109Smckusick #include <sys/syslog.h>
3738460Smckusick #include <netdb.h>
3838460Smckusick #include <rpc/rpc.h>
3938460Smckusick #include <rpc/pmap_clnt.h>
4038460Smckusick #include <rpc/pmap_prot.h>
4151667Smckusick #ifdef ISO
4251667Smckusick #include <netiso/iso.h>
4351667Smckusick #endif
4438460Smckusick #include <nfs/rpcv2.h>
4538460Smckusick #include <nfs/nfsv2.h>
4639681Smckusick #include "pathnames.h"
4753150Smckusick #ifdef DEBUG
4853150Smckusick #include <stdarg.h>
4953150Smckusick #endif
5038460Smckusick 
5138460Smckusick /*
5238460Smckusick  * Structures for keeping the mount list and export list
5338460Smckusick  */
5438460Smckusick struct mountlist {
5544015Smckusick 	struct mountlist *ml_next;
5638460Smckusick 	char	ml_host[RPCMNT_NAMELEN+1];
5738460Smckusick 	char	ml_dirp[RPCMNT_PATHLEN+1];
5838460Smckusick };
5938460Smckusick 
6051898Smckusick struct dirlist {
6151898Smckusick 	struct dirlist	*dp_left;
6251898Smckusick 	struct dirlist	*dp_right;
6351898Smckusick 	int		dp_flag;
6451898Smckusick 	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
6551898Smckusick 	char		dp_dirp[1];	/* Actually malloc'd to size of dir */
6651898Smckusick };
6751898Smckusick /* dp_flag bits */
6851898Smckusick #define	DP_DEFSET	0x1
6951898Smckusick 
7038460Smckusick struct exportlist {
7138460Smckusick 	struct exportlist *ex_next;
7251898Smckusick 	struct dirlist	*ex_dirl;
7351898Smckusick 	struct dirlist	*ex_defdir;
7451898Smckusick 	int		ex_flag;
7551898Smckusick 	fsid_t		ex_fs;
7651898Smckusick 	char		*ex_fsdir;
7738460Smckusick };
7851898Smckusick /* ex_flag bits */
7952109Smckusick #define	EX_LINKED	0x1
8038460Smckusick 
8151898Smckusick struct netmsk {
8251898Smckusick 	u_long	nt_net;
8351898Smckusick 	u_long	nt_mask;
8451898Smckusick 	char *nt_name;
8551898Smckusick };
8651898Smckusick 
8751667Smckusick union grouptypes {
8851667Smckusick 	struct hostent *gt_hostent;
8951898Smckusick 	struct netmsk	gt_net;
9051667Smckusick #ifdef ISO
9151667Smckusick 	struct sockaddr_iso *gt_isoaddr;
9251667Smckusick #endif
9351667Smckusick };
9451667Smckusick 
9538460Smckusick struct grouplist {
9651898Smckusick 	int gr_type;
9751667Smckusick 	union grouptypes gr_ptr;
9838460Smckusick 	struct grouplist *gr_next;
9938460Smckusick };
10051898Smckusick /* Group types */
10151898Smckusick #define	GT_NULL		0x0
10251898Smckusick #define	GT_HOST		0x1
10351898Smckusick #define	GT_NET		0x2
10451898Smckusick #define	GT_ISO		0x4
10538460Smckusick 
10651898Smckusick struct hostlist {
10751898Smckusick 	struct grouplist *ht_grp;
10851898Smckusick 	struct hostlist	 *ht_next;
10951667Smckusick };
11051667Smckusick 
11138460Smckusick /* Global defs */
11246709Sbostic int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
11351898Smckusick void get_exportlist(), send_umntall(), nextfield(), out_of_mem();
11451667Smckusick void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp();
11551898Smckusick void getexp_err(), hang_dirp(), add_dlist(), free_dir(), free_host();
11653150Smckusick void setnetgrent(), endnetgrent();
11751898Smckusick struct exportlist *ex_search(), *get_exp();
11851898Smckusick struct grouplist *get_grp();
11951898Smckusick char *realpath(), *add_expdir();
12051898Smckusick struct in_addr inet_makeaddr();
12151898Smckusick char *inet_ntoa();
12251898Smckusick struct dirlist *dirp_search();
12351898Smckusick struct hostlist *get_ht();
12451667Smckusick #ifdef ISO
12551667Smckusick struct iso_addr *iso_addr();
12651667Smckusick #endif
12751898Smckusick struct exportlist *exphead;
12844015Smckusick struct mountlist *mlhead;
12951898Smckusick struct grouplist *grphead;
13038460Smckusick char exname[MAXPATHLEN];
13151667Smckusick struct ucred def_anon = {
13251667Smckusick 	(u_short) 1,
13351667Smckusick 	(uid_t) -2,
13451667Smckusick 	1,
13551667Smckusick 	(gid_t) -2,
13651667Smckusick };
13744015Smckusick int root_only = 1;
13851898Smckusick int opt_flags;
13951898Smckusick /* Bits for above */
14051898Smckusick #define	OP_MAPROOT	0x01
14151898Smckusick #define	OP_MAPALL	0x02
14251898Smckusick #define	OP_KERB		0x04
14351898Smckusick #define	OP_MASK		0x08
14451898Smckusick #define	OP_NET		0x10
14551898Smckusick #define	OP_ISO		0x20
14651898Smckusick #define	OP_ALLDIRS	0x40
14751898Smckusick 
14838460Smckusick extern int errno;
14938460Smckusick #ifdef DEBUG
15038460Smckusick int debug = 1;
15151711Smckusick void	SYSLOG __P((int, const char *, ...));
15251711Smckusick #define syslog SYSLOG
15338460Smckusick #else
15438460Smckusick int debug = 0;
15538460Smckusick #endif
15638460Smckusick 
15738460Smckusick /*
15838460Smckusick  * Mountd server for NFS mount protocol as described in:
15939681Smckusick  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
16044015Smckusick  * The optional arguments are the exports file name
16139681Smckusick  * default: _PATH_EXPORTS
16244015Smckusick  * and "-n" to allow nonroot mount.
16338460Smckusick  */
16438460Smckusick main(argc, argv)
16538460Smckusick 	int argc;
16644015Smckusick 	char **argv;
16738460Smckusick {
16838460Smckusick 	SVCXPRT *transp;
16944015Smckusick 	int c;
17044015Smckusick 	extern int optind;
17144015Smckusick 	extern char *optarg;
17238460Smckusick 
17344015Smckusick 	while ((c = getopt(argc, argv, "n")) != EOF)
17444015Smckusick 		switch (c) {
17544015Smckusick 		case 'n':
17644015Smckusick 			root_only = 0;
17744015Smckusick 			break;
17844015Smckusick 		default:
17944015Smckusick 			fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
18044015Smckusick 			exit(1);
18144015Smckusick 		};
18244015Smckusick 	argc -= optind;
18344015Smckusick 	argv += optind;
18451898Smckusick 	grphead = (struct grouplist *)0;
18551898Smckusick 	exphead = (struct exportlist *)0;
18644015Smckusick 	mlhead = (struct mountlist *)0;
18744015Smckusick 	if (argc == 1) {
18844015Smckusick 		strncpy(exname, *argv, MAXPATHLEN-1);
18944015Smckusick 		exname[MAXPATHLEN-1] = '\0';
19044015Smckusick 	} else
19144015Smckusick 		strcpy(exname, _PATH_EXPORTS);
19244338Smckusick 	openlog("mountd:", LOG_PID, LOG_DAEMON);
19351667Smckusick 	if (debug)
19451667Smckusick 		fprintf(stderr,"Getting export list.\n");
19544015Smckusick 	get_exportlist();
19651667Smckusick 	if (debug)
19751667Smckusick 		fprintf(stderr,"Getting mount list.\n");
19844015Smckusick 	get_mountlist();
19951667Smckusick 	if (debug)
20051667Smckusick 		fprintf(stderr,"Here we go.\n");
20138460Smckusick 	if (debug == 0) {
20244690Skarels 		daemon(0, 0);
20338460Smckusick 		signal(SIGINT, SIG_IGN);
20438460Smckusick 		signal(SIGQUIT, SIG_IGN);
20538460Smckusick 	}
20638460Smckusick 	signal(SIGHUP, get_exportlist);
20744015Smckusick 	signal(SIGTERM, send_umntall);
20840494Smckusick 	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
20940494Smckusick 	  if (pidfile != NULL) {
21040494Smckusick 		fprintf(pidfile, "%d\n", getpid());
21140494Smckusick 		fclose(pidfile);
21240494Smckusick 	  }
21340494Smckusick 	}
21438460Smckusick 	if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
21538460Smckusick 		syslog(LOG_ERR, "Can't create socket");
21638460Smckusick 		exit(1);
21738460Smckusick 	}
21838460Smckusick 	pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
21951667Smckusick 	if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
22051667Smckusick 	    IPPROTO_UDP)) {
22138460Smckusick 		syslog(LOG_ERR, "Can't register mount");
22238460Smckusick 		exit(1);
22338460Smckusick 	}
22438460Smckusick 	svc_run();
22538460Smckusick 	syslog(LOG_ERR, "Mountd died");
22644690Skarels 	exit(1);
22738460Smckusick }
22838460Smckusick 
22938460Smckusick /*
23038460Smckusick  * The mount rpc service
23138460Smckusick  */
23238460Smckusick mntsrv(rqstp, transp)
23338460Smckusick 	register struct svc_req *rqstp;
23438460Smckusick 	register SVCXPRT *transp;
23538460Smckusick {
23638460Smckusick 	register struct exportlist *ep;
23751898Smckusick 	register struct dirlist *dp;
23838460Smckusick 	nfsv2fh_t nfh;
23938460Smckusick 	struct authunix_parms *ucr;
24038460Smckusick 	struct stat stb;
24151898Smckusick 	struct statfs fsb;
24238460Smckusick 	struct hostent *hp;
24339681Smckusick 	u_long saddr;
24451667Smckusick 	char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN];
24551898Smckusick 	int bad = ENOENT, omask, defset;
24639681Smckusick 	uid_t uid = -2;
24738460Smckusick 
24838460Smckusick 	/* Get authorization */
24938460Smckusick 	switch (rqstp->rq_cred.oa_flavor) {
25038460Smckusick 	case AUTH_UNIX:
25138460Smckusick 		ucr = (struct authunix_parms *)rqstp->rq_clntcred;
25239681Smckusick 		uid = ucr->aup_uid;
25339681Smckusick 		break;
25438460Smckusick 	case AUTH_NULL:
25538460Smckusick 	default:
25639681Smckusick 		break;
25738460Smckusick 	}
25838460Smckusick 
25939681Smckusick 	saddr = transp->xp_raddr.sin_addr.s_addr;
26039681Smckusick 	hp = (struct hostent *)0;
26138460Smckusick 	switch (rqstp->rq_proc) {
26239681Smckusick 	case NULLPROC:
26339681Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
26439681Smckusick 			syslog(LOG_ERR, "Can't send reply");
26539681Smckusick 		return;
26638460Smckusick 	case RPCMNT_MOUNT:
26751667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
26839681Smckusick 			svcerr_weakauth(transp);
26939681Smckusick 			return;
27039681Smckusick 		}
27151667Smckusick 		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
27238460Smckusick 			svcerr_decode(transp);
27338460Smckusick 			return;
27438460Smckusick 		}
27538460Smckusick 
27651667Smckusick 		/*
27751667Smckusick 		 * Get the real pathname and make sure it is a directory
27851667Smckusick 		 * that exists.
27951667Smckusick 		 */
28051898Smckusick 		if (realpath(rpcpath, dirpath) == 0 ||
28151898Smckusick 		    stat(dirpath, &stb) < 0 ||
28251898Smckusick 		    (stb.st_mode & S_IFMT) != S_IFDIR ||
28351898Smckusick 		    statfs(dirpath, &fsb) < 0) {
28451667Smckusick 			chdir("/");	/* Just in case realpath doesn't */
28551667Smckusick 			if (debug)
28651898Smckusick 				fprintf(stderr, "stat failed on %s\n", dirpath);
28738460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
28838460Smckusick 				syslog(LOG_ERR, "Can't send reply");
28938460Smckusick 			return;
29038460Smckusick 		}
29138460Smckusick 
29238460Smckusick 		/* Check in the exports list */
29338460Smckusick 		omask = sigblock(sigmask(SIGHUP));
29451898Smckusick 		ep = ex_search(&fsb.f_fsid);
29551898Smckusick 		defset = 0;
29651898Smckusick 		if (ep && (chk_host(ep->ex_defdir, saddr, &defset) ||
29751898Smckusick 		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
29851898Smckusick 		     chk_host(dp, saddr, &defset)) ||
29951898Smckusick 		     (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
30051898Smckusick 		      scan_tree(ep->ex_dirl, saddr) == 0))) {
30151667Smckusick 			/* Get the file handle */
30251667Smckusick 			bzero((caddr_t)&nfh, sizeof(nfh));
30351667Smckusick 			if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
30451667Smckusick 				bad = errno;
30551898Smckusick 				syslog(LOG_ERR, "Can't get fh for %s", dirpath);
30651667Smckusick 				if (!svc_sendreply(transp, xdr_long,
30751667Smckusick 				    (caddr_t)&bad))
30851667Smckusick 					syslog(LOG_ERR, "Can't send reply");
30951667Smckusick 				sigsetmask(omask);
31051667Smckusick 				return;
31151667Smckusick 			}
31251667Smckusick 			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
31338460Smckusick 				syslog(LOG_ERR, "Can't send reply");
31451667Smckusick 			if (hp == NULL)
31551667Smckusick 				hp = gethostbyaddr((caddr_t)&saddr,
31651667Smckusick 				    sizeof(saddr), AF_INET);
31751667Smckusick 			if (hp)
31851667Smckusick 				add_mlist(hp->h_name, dirpath);
31951667Smckusick 			else
32051667Smckusick 				add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
32151667Smckusick 					dirpath);
32251667Smckusick 			if (debug)
32351667Smckusick 				fprintf(stderr,"Mount successfull.\n");
32451898Smckusick 		} else {
32551898Smckusick 			bad = EACCES;
32651898Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
32751898Smckusick 				syslog(LOG_ERR, "Can't send reply");
32838460Smckusick 		}
32951667Smckusick 		sigsetmask(omask);
33038460Smckusick 		return;
33138460Smckusick 	case RPCMNT_DUMP:
33238460Smckusick 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
33338460Smckusick 			syslog(LOG_ERR, "Can't send reply");
33438460Smckusick 		return;
33538460Smckusick 	case RPCMNT_UMOUNT:
33651667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
33739681Smckusick 			svcerr_weakauth(transp);
33839681Smckusick 			return;
33939681Smckusick 		}
34038460Smckusick 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
34138460Smckusick 			svcerr_decode(transp);
34238460Smckusick 			return;
34338460Smckusick 		}
34438460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
34538460Smckusick 			syslog(LOG_ERR, "Can't send reply");
34644015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
34744015Smckusick 		if (hp)
34844015Smckusick 			del_mlist(hp->h_name, dirpath);
34951667Smckusick 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
35038460Smckusick 		return;
35138460Smckusick 	case RPCMNT_UMNTALL:
35251667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
35339681Smckusick 			svcerr_weakauth(transp);
35439681Smckusick 			return;
35539681Smckusick 		}
35638460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
35738460Smckusick 			syslog(LOG_ERR, "Can't send reply");
35844015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
35944015Smckusick 		if (hp)
36044015Smckusick 			del_mlist(hp->h_name, (char *)0);
36151667Smckusick 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)0);
36238460Smckusick 		return;
36338460Smckusick 	case RPCMNT_EXPORT:
36438460Smckusick 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)0))
36538460Smckusick 			syslog(LOG_ERR, "Can't send reply");
36638460Smckusick 		return;
36738460Smckusick 	default:
36838460Smckusick 		svcerr_noproc(transp);
36938460Smckusick 		return;
37038460Smckusick 	}
37138460Smckusick }
37238460Smckusick 
37338460Smckusick /*
37438460Smckusick  * Xdr conversion for a dirpath string
37538460Smckusick  */
37638460Smckusick xdr_dir(xdrsp, dirp)
37738460Smckusick 	XDR *xdrsp;
37838460Smckusick 	char *dirp;
37938460Smckusick {
38038460Smckusick 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
38138460Smckusick }
38238460Smckusick 
38338460Smckusick /*
38438460Smckusick  * Xdr routine to generate fhstatus
38538460Smckusick  */
38638460Smckusick xdr_fhs(xdrsp, nfh)
38738460Smckusick 	XDR *xdrsp;
38838460Smckusick 	nfsv2fh_t *nfh;
38938460Smckusick {
39038460Smckusick 	int ok = 0;
39138460Smckusick 
39238460Smckusick 	if (!xdr_long(xdrsp, &ok))
39338460Smckusick 		return (0);
39438460Smckusick 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
39538460Smckusick }
39638460Smckusick 
39738460Smckusick xdr_mlist(xdrsp, cp)
39838460Smckusick 	XDR *xdrsp;
39938460Smckusick 	caddr_t cp;
40038460Smckusick {
40144015Smckusick 	register struct mountlist *mlp;
40238460Smckusick 	int true = 1;
40338460Smckusick 	int false = 0;
40438460Smckusick 	char *strp;
40538460Smckusick 
40644015Smckusick 	mlp = mlhead;
40744015Smckusick 	while (mlp) {
40844015Smckusick 		if (!xdr_bool(xdrsp, &true))
40944015Smckusick 			return (0);
41044015Smckusick 		strp = &mlp->ml_host[0];
41144015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
41244015Smckusick 			return (0);
41344015Smckusick 		strp = &mlp->ml_dirp[0];
41444015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
41544015Smckusick 			return (0);
41644015Smckusick 		mlp = mlp->ml_next;
41738460Smckusick 	}
41838460Smckusick 	if (!xdr_bool(xdrsp, &false))
41938460Smckusick 		return (0);
42038460Smckusick 	return (1);
42138460Smckusick }
42238460Smckusick 
42338460Smckusick /*
42438460Smckusick  * Xdr conversion for export list
42538460Smckusick  */
42638460Smckusick xdr_explist(xdrsp, cp)
42738460Smckusick 	XDR *xdrsp;
42838460Smckusick 	caddr_t cp;
42938460Smckusick {
43038460Smckusick 	register struct exportlist *ep;
43138460Smckusick 	int false = 0;
43238460Smckusick 	int omask;
43338460Smckusick 
43438460Smckusick 	omask = sigblock(sigmask(SIGHUP));
43551898Smckusick 	ep = exphead;
43651898Smckusick 	while (ep) {
43751898Smckusick 		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir))
43838460Smckusick 			goto errout;
43938460Smckusick 		ep = ep->ex_next;
44038460Smckusick 	}
44138460Smckusick 	sigsetmask(omask);
44238460Smckusick 	if (!xdr_bool(xdrsp, &false))
44338460Smckusick 		return (0);
44438460Smckusick 	return (1);
44538460Smckusick errout:
44638460Smckusick 	sigsetmask(omask);
44738460Smckusick 	return (0);
44838460Smckusick }
44938460Smckusick 
45051898Smckusick /*
45151898Smckusick  * Called from xdr_explist() to traverse the tree and export the
45251898Smckusick  * directory paths.
45351898Smckusick  */
45451898Smckusick put_exlist(dp, xdrsp, adp)
45551898Smckusick 	register struct dirlist *dp;
45651898Smckusick 	XDR *xdrsp;
45751898Smckusick 	struct dirlist *adp;
45851898Smckusick {
45951898Smckusick 	register struct grouplist *grp;
46051898Smckusick 	register struct hostlist *hp;
46151898Smckusick 	struct in_addr inaddr;
46251898Smckusick 	int true = 1;
46351898Smckusick 	int false = 0;
46451898Smckusick 	int gotalldir = 0;
46551898Smckusick 	char *strp;
46651898Smckusick 
46751898Smckusick 	if (dp) {
46851898Smckusick 		if (put_exlist(dp->dp_left, xdrsp, adp))
46951898Smckusick 			return (1);
47051898Smckusick 		if (!xdr_bool(xdrsp, &true))
47151898Smckusick 			return (1);
47251898Smckusick 		strp = dp->dp_dirp;
47351898Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
47451898Smckusick 			return (1);
47551898Smckusick 		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp))
47651898Smckusick 			gotalldir = 1;
47751898Smckusick 		if ((dp->dp_flag & DP_DEFSET) == 0 &&
47851898Smckusick 		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
47951898Smckusick 			hp = dp->dp_hosts;
48051898Smckusick 			while (hp) {
48151898Smckusick 				grp = hp->ht_grp;
48251898Smckusick 				if (grp->gr_type == GT_HOST) {
48351898Smckusick 					if (!xdr_bool(xdrsp, &true))
48451898Smckusick 						return (1);
48551898Smckusick 					strp = grp->gr_ptr.gt_hostent->h_name;
48651898Smckusick 					if (!xdr_string(xdrsp, &strp,
48751898Smckusick 					    RPCMNT_NAMELEN))
48851898Smckusick 						return (1);
48951898Smckusick 				} else if (grp->gr_type == GT_NET) {
49051898Smckusick 					if (!xdr_bool(xdrsp, &true))
49151898Smckusick 						return (1);
49251898Smckusick 					strp = grp->gr_ptr.gt_net.nt_name;
49351898Smckusick 					if (!xdr_string(xdrsp, &strp,
49451898Smckusick 					    RPCMNT_NAMELEN))
49551898Smckusick 						return (1);
49651898Smckusick 				}
49751898Smckusick 				hp = hp->ht_next;
49851898Smckusick 				if (gotalldir && hp == (struct hostlist *)0) {
49951898Smckusick 					hp = adp->dp_hosts;
50051898Smckusick 					gotalldir = 0;
50151898Smckusick 				}
50251898Smckusick 			}
50351898Smckusick 		}
50451898Smckusick 		if (!xdr_bool(xdrsp, &false))
50551898Smckusick 			return (1);
50651898Smckusick 		if (put_exlist(dp->dp_right, xdrsp, adp))
50751898Smckusick 			return (1);
50851898Smckusick 	}
50951898Smckusick 	return (0);
51051898Smckusick }
51151898Smckusick 
51238460Smckusick #define LINESIZ	10240
51338460Smckusick char line[LINESIZ];
51451898Smckusick FILE *exp_file;
51538460Smckusick 
51638460Smckusick /*
51738460Smckusick  * Get the export list
51838460Smckusick  */
51946709Sbostic void
52038460Smckusick get_exportlist()
52138460Smckusick {
52238460Smckusick 	register struct exportlist *ep, *ep2;
52351898Smckusick 	register struct grouplist *grp, *tgrp;
52451898Smckusick 	struct exportlist **epp;
52551898Smckusick 	struct dirlist *dirhead;
52651898Smckusick 	struct stat sb;
52752109Smckusick 	struct statfs fsb, *fsp;
52851898Smckusick 	struct hostent *hpe;
52951898Smckusick 	struct ucred anon;
53052109Smckusick 	struct ufs_args targs;
53153150Smckusick 	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
53253150Smckusick 	int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
53338460Smckusick 
53438460Smckusick 	/*
53538460Smckusick 	 * First, get rid of the old list
53638460Smckusick 	 */
53751898Smckusick 	ep = exphead;
53851898Smckusick 	while (ep) {
53938460Smckusick 		ep2 = ep;
54038460Smckusick 		ep = ep->ex_next;
54144015Smckusick 		free_exp(ep2);
54238460Smckusick 	}
54351898Smckusick 	exphead = (struct exportlist *)0;
54438460Smckusick 
54551898Smckusick 	grp = grphead;
54651898Smckusick 	while (grp) {
54751898Smckusick 		tgrp = grp;
54851898Smckusick 		grp = grp->gr_next;
54951898Smckusick 		free_grp(tgrp);
55051667Smckusick 	}
55151898Smckusick 	grphead = (struct grouplist *)0;
55251667Smckusick 
55338460Smckusick 	/*
55452109Smckusick 	 * And delete exports that are in the kernel for all local
55552109Smckusick 	 * file systems.
55652109Smckusick 	 * XXX: Should know how to handle all local exportable file systems
55752109Smckusick 	 *      instead of just MOUNT_UFS.
55852109Smckusick 	 */
559*53214Smckusick 	num = getmntinfo(&fsp, MNT_NOWAIT);
56052109Smckusick 	for (i = 0; i < num; i++) {
56152109Smckusick 		if (fsp->f_type == MOUNT_UFS) {
56252109Smckusick 			targs.fspec = (char *)0;
56352109Smckusick 			targs.exflags = MNT_DELEXPORT;
56452109Smckusick 			if (mount(fsp->f_type, fsp->f_mntonname,
56552109Smckusick 			    fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0)
56652109Smckusick 				syslog(LOG_ERR, "Can't del exports %s",
56752109Smckusick 				       fsp->f_mntonname);
56852109Smckusick 		}
56952109Smckusick 		fsp++;
57052109Smckusick 	}
57152109Smckusick 
57252109Smckusick 	/*
57338460Smckusick 	 * Read in the exports file and build the list, calling
57451667Smckusick 	 * mount() as we go along to push the export rules into the kernel.
57538460Smckusick 	 */
57651898Smckusick 	if ((exp_file = fopen(exname, "r")) == NULL) {
57738460Smckusick 		syslog(LOG_ERR, "Can't open %s", exname);
57838460Smckusick 		exit(2);
57938460Smckusick 	}
58051898Smckusick 	dirhead = (struct dirlist *)0;
58151898Smckusick 	while (get_line()) {
58251667Smckusick 		if (debug)
58351667Smckusick 			fprintf(stderr,"Got line %s\n",line);
58438460Smckusick 		cp = line;
58538460Smckusick 		nextfield(&cp, &endcp);
58651667Smckusick 		if (*cp == '#')
58751667Smckusick 			goto nextline;
58851898Smckusick 
58951898Smckusick 		/*
59051898Smckusick 		 * Set defaults.
59151898Smckusick 		 */
59251898Smckusick 		has_host = FALSE;
59351898Smckusick 		anon = def_anon;
59451667Smckusick 		exflags = MNT_EXPORTED;
59551898Smckusick 		got_nondir = 0;
59651898Smckusick 		opt_flags = 0;
59751898Smckusick 		ep = (struct exportlist *)0;
59844015Smckusick 
59944015Smckusick 		/*
60044015Smckusick 		 * Create new exports list entry
60144015Smckusick 		 */
60238460Smckusick 		len = endcp-cp;
60353150Smckusick 		tgrp = grp = get_grp();
60451898Smckusick 		while (len > 0) {
60551898Smckusick 			if (len > RPCMNT_NAMELEN) {
60653150Smckusick 			    getexp_err(ep, tgrp);
60751898Smckusick 			    goto nextline;
60851667Smckusick 			}
60945271Smckusick 			if (*cp == '-') {
61051898Smckusick 			    if (ep == (struct exportlist *)0) {
61153150Smckusick 				getexp_err(ep, tgrp);
61251898Smckusick 				goto nextline;
61351898Smckusick 			    }
61451898Smckusick 			    if (debug)
61551898Smckusick 				fprintf(stderr, "doing opt %s\n", cp);
61651898Smckusick 			    got_nondir = 1;
61751898Smckusick 			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
61851898Smckusick 				&exflags, &anon)) {
61953150Smckusick 				getexp_err(ep, tgrp);
62051898Smckusick 				goto nextline;
62151898Smckusick 			    }
62251898Smckusick 			} else if (*cp == '/') {
62351898Smckusick 			    savedc = *endcp;
62451898Smckusick 			    *endcp = '\0';
62551898Smckusick 			    if (stat(cp, &sb) >= 0 &&
62651898Smckusick 				(sb.st_mode & S_IFMT) == S_IFDIR &&
62751898Smckusick 				statfs(cp, &fsb) >= 0) {
62851898Smckusick 				if (got_nondir) {
62951898Smckusick 				    syslog(LOG_ERR, "Dirs must be first");
63053150Smckusick 				    getexp_err(ep, tgrp);
63151898Smckusick 				    goto nextline;
63251898Smckusick 				}
63351898Smckusick 				if (ep) {
63451898Smckusick 				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
63551898Smckusick 					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
63653150Smckusick 					getexp_err(ep, tgrp);
63751898Smckusick 					goto nextline;
63851898Smckusick 				    }
63951667Smckusick 				} else {
64051898Smckusick 				    /*
64151898Smckusick 				     * See if this directory is already
64251898Smckusick 				     * in the list.
64351898Smckusick 				     */
64451898Smckusick 				    ep = ex_search(&fsb.f_fsid);
64551898Smckusick 				    if (ep == (struct exportlist *)0) {
64651898Smckusick 					ep = get_exp();
64751898Smckusick 					ep->ex_fs = fsb.f_fsid;
64851898Smckusick 					ep->ex_fsdir = (char *)
64951898Smckusick 					    malloc(strlen(fsb.f_mntonname) + 1);
65051898Smckusick 					if (ep->ex_fsdir)
65151898Smckusick 					    strcpy(ep->ex_fsdir,
65251898Smckusick 						fsb.f_mntonname);
65351898Smckusick 					else
65451898Smckusick 					    out_of_mem();
65551898Smckusick 					if (debug)
65651898Smckusick 					  fprintf(stderr,
65751898Smckusick 					      "Making new ep fs=0x%x,0x%x\n",
65851898Smckusick 					      fsb.f_fsid.val[0],
65951898Smckusick 					      fsb.f_fsid.val[1]);
66051898Smckusick 				    } else if (debug)
66151898Smckusick 					fprintf(stderr,
66251898Smckusick 					    "Found ep fs=0x%x,0x%x\n",
66351898Smckusick 					    fsb.f_fsid.val[0],
66451898Smckusick 					    fsb.f_fsid.val[1]);
66538460Smckusick 				}
66651898Smckusick 
66751898Smckusick 				/*
66851898Smckusick 				 * Add dirpath to export mount point.
66951898Smckusick 				 */
67051898Smckusick 				dirp = add_expdir(&dirhead, cp, len);
67151898Smckusick 				dirplen = len;
67251898Smckusick 			    } else {
67353150Smckusick 				getexp_err(ep, tgrp);
67451898Smckusick 				goto nextline;
67551898Smckusick 			    }
67651898Smckusick 			    *endcp = savedc;
67751898Smckusick 			} else {
67851898Smckusick 			    savedc = *endcp;
67951898Smckusick 			    *endcp = '\0';
68051898Smckusick 			    got_nondir = 1;
68153150Smckusick 			    if (ep == (struct exportlist *)0) {
68253150Smckusick 				getexp_err(ep, tgrp);
68351898Smckusick 				goto nextline;
68451898Smckusick 			    }
68553150Smckusick 
68653150Smckusick 			    /*
68753150Smckusick 			     * Get the host or netgroup.
68853150Smckusick 			     */
68953150Smckusick 			    setnetgrent(cp);
69053150Smckusick 			    netgrp = getnetgrent(&hst, &usr, &dom);
69153150Smckusick 			    do {
69253150Smckusick 				if (has_host) {
69353150Smckusick 				    grp->gr_next = get_grp();
69453150Smckusick 				    grp = grp->gr_next;
69553150Smckusick 				}
69653150Smckusick 				if (netgrp) {
69753150Smckusick 				    if (get_host(hst, grp)) {
69853150Smckusick 					syslog(LOG_ERR, "Bad netgroup %s", cp);
69953150Smckusick 					getexp_err(ep, tgrp);
70053150Smckusick 					goto nextline;
70153150Smckusick 				    }
70253150Smckusick 				} else if (get_host(cp, grp)) {
70353150Smckusick 				    getexp_err(ep, tgrp);
70453150Smckusick 				    goto nextline;
70553150Smckusick 				}
70653150Smckusick 				has_host = TRUE;
70753150Smckusick 			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
70853150Smckusick 			    endnetgrent();
70951898Smckusick 			    *endcp = savedc;
71038460Smckusick 			}
71138460Smckusick 			cp = endcp;
71238460Smckusick 			nextfield(&cp, &endcp);
71345271Smckusick 			len = endcp - cp;
71438460Smckusick 		}
71551898Smckusick 		if (check_options(dirhead)) {
71653150Smckusick 			getexp_err(ep, tgrp);
71751898Smckusick 			goto nextline;
71851898Smckusick 		}
71951898Smckusick 		if (!has_host) {
72051898Smckusick 			grp->gr_type = GT_HOST;
72151667Smckusick 			if (debug)
72251667Smckusick 				fprintf(stderr,"Adding a default entry\n");
72351667Smckusick 			/* add a default group and make the grp list NULL */
72451667Smckusick 			hpe = (struct hostent *)malloc(sizeof(struct hostent));
72551898Smckusick 			if (hpe == (struct hostent *)0)
72651898Smckusick 				out_of_mem();
72751898Smckusick 			hpe->h_name = "Default";
72851667Smckusick 			hpe->h_addrtype = AF_INET;
72951667Smckusick 			hpe->h_length = sizeof (u_long);
73051712Smckusick 			hpe->h_addr_list = (char **)0;
73151898Smckusick 			grp->gr_ptr.gt_hostent = hpe;
73253150Smckusick 
73353150Smckusick 		/*
73453150Smckusick 		 * Don't allow a network export coincide with a list of
73553150Smckusick 		 * host(s) on the same line.
73653150Smckusick 		 */
73753150Smckusick 		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
73853150Smckusick 			getexp_err(ep, tgrp);
73953150Smckusick 			goto nextline;
74051667Smckusick 		}
74153150Smckusick 
74253150Smckusick 		/*
74353150Smckusick 		 * Loop through hosts, pushing the exports into the kernel.
74453150Smckusick 		 * After loop, tgrp points to the start of the list and
74553150Smckusick 		 * grp points to the last entry in the list.
74653150Smckusick 		 */
74753150Smckusick 		grp = tgrp;
74853150Smckusick 		do {
74953150Smckusick 		    if (do_mount(ep, grp, exflags, &anon, dirp,
75051898Smckusick 			dirplen, &fsb)) {
75153150Smckusick 			getexp_err(ep, tgrp);
75251898Smckusick 			goto nextline;
75353150Smckusick 		    }
75453150Smckusick 		} while (grp->gr_next && (grp = grp->gr_next));
75551898Smckusick 
75651898Smckusick 		/*
75751898Smckusick 		 * Success. Update the data structures.
75851898Smckusick 		 */
75951898Smckusick 		if (has_host) {
76053150Smckusick 			hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS));
76151898Smckusick 			grp->gr_next = grphead;
76253150Smckusick 			grphead = tgrp;
76351898Smckusick 		} else {
76451898Smckusick 			hang_dirp(dirhead, (struct grouplist *)0, ep,
76553150Smckusick 			(opt_flags & OP_ALLDIRS));
76651898Smckusick 			free_grp(grp);
76751898Smckusick 		}
76851898Smckusick 		dirhead = (struct dirlist *)0;
76951898Smckusick 		if ((ep->ex_flag & EX_LINKED) == 0) {
77051898Smckusick 			ep2 = exphead;
77151898Smckusick 			epp = &exphead;
77251898Smckusick 
77351898Smckusick 			/*
77451898Smckusick 			 * Insert in the list in alphabetical order.
77551898Smckusick 			 */
77651898Smckusick 			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
77751898Smckusick 				epp = &ep2->ex_next;
77851898Smckusick 				ep2 = ep2->ex_next;
77951898Smckusick 			}
78051898Smckusick 			if (ep2)
78151898Smckusick 				ep->ex_next = ep2;
78251898Smckusick 			*epp = ep;
78351898Smckusick 			ep->ex_flag |= EX_LINKED;
78451898Smckusick 		}
78551898Smckusick nextline:
78651898Smckusick 		if (dirhead) {
78751898Smckusick 			free_dir(dirhead);
78851898Smckusick 			dirhead = (struct dirlist *)0;
78951898Smckusick 		}
79051898Smckusick 	}
79151898Smckusick 	fclose(exp_file);
79251898Smckusick }
79351898Smckusick 
79451898Smckusick /*
79551898Smckusick  * Allocate an export list element
79651898Smckusick  */
79751898Smckusick struct exportlist *
79851898Smckusick get_exp()
79951898Smckusick {
80051898Smckusick 	register struct exportlist *ep;
80151898Smckusick 
80251898Smckusick 	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
80351898Smckusick 	if (ep == (struct exportlist *)0)
80451898Smckusick 		out_of_mem();
80551898Smckusick 	bzero((caddr_t)ep, sizeof (struct exportlist));
80651898Smckusick 	return (ep);
80751898Smckusick }
80851898Smckusick 
80951898Smckusick /*
81051898Smckusick  * Allocate a group list element
81151898Smckusick  */
81251898Smckusick struct grouplist *
81351898Smckusick get_grp()
81451898Smckusick {
81551898Smckusick 	register struct grouplist *gp;
81651898Smckusick 
81751898Smckusick 	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
81851898Smckusick 	if (gp == (struct grouplist *)0)
81951898Smckusick 		out_of_mem();
82051898Smckusick 	bzero((caddr_t)gp, sizeof (struct grouplist));
82151898Smckusick 	return (gp);
82251898Smckusick }
82351898Smckusick 
82451898Smckusick /*
82551898Smckusick  * Clean up upon an error in get_exportlist().
82651898Smckusick  */
82751898Smckusick void
82851898Smckusick getexp_err(ep, grp)
82951898Smckusick 	struct exportlist *ep;
83051898Smckusick 	struct grouplist *grp;
83151898Smckusick {
83253150Smckusick 	struct grouplist *tgrp;
83351898Smckusick 
83451898Smckusick 	syslog(LOG_ERR, "Bad exports list line %s", line);
83551898Smckusick 	if (ep && ep->ex_next == (struct exportlist *)0)
83651898Smckusick 		free_exp(ep);
83753150Smckusick 	while (grp) {
83853150Smckusick 		tgrp = grp;
83953150Smckusick 		grp = grp->gr_next;
84053150Smckusick 		free_grp(tgrp);
84153150Smckusick 	}
84251898Smckusick }
84351898Smckusick 
84451898Smckusick /*
84551898Smckusick  * Search the export list for a matching fs.
84651898Smckusick  */
84751898Smckusick struct exportlist *
84851898Smckusick ex_search(fsid)
84952109Smckusick 	fsid_t *fsid;
85051898Smckusick {
85151898Smckusick 	register struct exportlist *ep;
85251898Smckusick 
85351898Smckusick 	ep = exphead;
85451898Smckusick 	while (ep) {
85551898Smckusick 		if (ep->ex_fs.val[0] == fsid->val[0] &&
85651898Smckusick 		    ep->ex_fs.val[1] == fsid->val[1])
85751898Smckusick 			return (ep);
85851898Smckusick 		ep = ep->ex_next;
85951898Smckusick 	}
86051898Smckusick 	return (ep);
86151898Smckusick }
86251898Smckusick 
86351898Smckusick /*
86451898Smckusick  * Add a directory path to the list.
86551898Smckusick  */
86651898Smckusick char *
86751898Smckusick add_expdir(dpp, cp, len)
86851898Smckusick 	struct dirlist **dpp;
86951898Smckusick 	char *cp;
87051898Smckusick 	int len;
87151898Smckusick {
87251898Smckusick 	register struct dirlist *dp;
87351898Smckusick 
87451898Smckusick 	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
87551898Smckusick 	dp->dp_left = *dpp;
87651898Smckusick 	dp->dp_right = (struct dirlist *)0;
87751898Smckusick 	dp->dp_flag = 0;
87851898Smckusick 	dp->dp_hosts = (struct hostlist *)0;
87951898Smckusick 	strcpy(dp->dp_dirp, cp);
88051898Smckusick 	*dpp = dp;
88151898Smckusick 	return (dp->dp_dirp);
88251898Smckusick }
88351898Smckusick 
88451898Smckusick /*
88551898Smckusick  * Hang the dir list element off the dirpath binary tree as required
88651898Smckusick  * and update the entry for host.
88751898Smckusick  */
88851898Smckusick void
88951898Smckusick hang_dirp(dp, grp, ep, alldirs)
89051898Smckusick 	register struct dirlist *dp;
89151898Smckusick 	struct grouplist *grp;
89251898Smckusick 	struct exportlist *ep;
89351898Smckusick 	int alldirs;
89451898Smckusick {
89551898Smckusick 	register struct hostlist *hp;
89651898Smckusick 	struct dirlist *dp2;
89751898Smckusick 
89851898Smckusick 	if (alldirs) {
89951898Smckusick 		if (ep->ex_defdir)
90051898Smckusick 			free((caddr_t)dp);
90151898Smckusick 		else
90251898Smckusick 			ep->ex_defdir = dp;
90351898Smckusick 		if (grp) {
90451898Smckusick 			hp = get_ht();
90551898Smckusick 			hp->ht_grp = grp;
90651898Smckusick 			hp->ht_next = ep->ex_defdir->dp_hosts;
90751898Smckusick 			ep->ex_defdir->dp_hosts = hp;
90851898Smckusick 		} else
90951898Smckusick 			ep->ex_defdir->dp_flag |= DP_DEFSET;
91051898Smckusick 	} else {
91153150Smckusick 
91253150Smckusick 		/*
91353150Smckusick 		 * Loop throught the directories adding them to the tree.
91453150Smckusick 		 */
91551898Smckusick 		while (dp) {
91651898Smckusick 			dp2 = dp->dp_left;
91753150Smckusick 			add_dlist(&ep->ex_dirl, dp, grp);
91851898Smckusick 			dp = dp2;
91951898Smckusick 		}
92051898Smckusick 	}
92151898Smckusick }
92251898Smckusick 
92351898Smckusick /*
92451898Smckusick  * Traverse the binary tree either updating a node that is already there
92551898Smckusick  * for the new directory or adding the new node.
92651898Smckusick  */
92751898Smckusick void
92853150Smckusick add_dlist(dpp, newdp, grp)
92951898Smckusick 	struct dirlist **dpp;
93051898Smckusick 	struct dirlist *newdp;
93153150Smckusick 	register struct grouplist *grp;
93251898Smckusick {
93351898Smckusick 	register struct dirlist *dp;
93453150Smckusick 	register struct hostlist *hp;
93551898Smckusick 	int cmp;
93651898Smckusick 
93751898Smckusick 	dp = *dpp;
93851898Smckusick 	if (dp) {
93951898Smckusick 		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
94051898Smckusick 		if (cmp > 0) {
94153150Smckusick 			add_dlist(&dp->dp_left, newdp, grp);
94251898Smckusick 			return;
94351898Smckusick 		} else if (cmp < 0) {
94453150Smckusick 			add_dlist(&dp->dp_right, newdp, grp);
94551898Smckusick 			return;
94651898Smckusick 		} else
94751898Smckusick 			free((caddr_t)newdp);
94851898Smckusick 	} else {
94951898Smckusick 		dp = newdp;
95051898Smckusick 		dp->dp_left = (struct dirlist *)0;
95151898Smckusick 		*dpp = dp;
95251898Smckusick 	}
95353150Smckusick 	if (grp) {
95453150Smckusick 
95553150Smckusick 		/*
95653150Smckusick 		 * Hang all of the host(s) off of the directory point.
95753150Smckusick 		 */
95853150Smckusick 		do {
95953150Smckusick 			hp = get_ht();
96053150Smckusick 			hp->ht_grp = grp;
96153150Smckusick 			hp->ht_next = dp->dp_hosts;
96253150Smckusick 			dp->dp_hosts = hp;
96353150Smckusick 			grp = grp->gr_next;
96453150Smckusick 		} while (grp);
96551898Smckusick 	} else
96651898Smckusick 		dp->dp_flag |= DP_DEFSET;
96751898Smckusick }
96851898Smckusick 
96951898Smckusick /*
97051898Smckusick  * Search for a dirpath on the export point.
97151898Smckusick  */
97251898Smckusick struct dirlist *
97351898Smckusick dirp_search(dp, dirpath)
97451898Smckusick 	register struct dirlist *dp;
97551898Smckusick 	char *dirpath;
97651898Smckusick {
97751898Smckusick 	register int cmp;
97851898Smckusick 
97951898Smckusick 	if (dp) {
98051898Smckusick 		cmp = strcmp(dp->dp_dirp, dirpath);
98151898Smckusick 		if (cmp > 0)
98251898Smckusick 			return (dirp_search(dp->dp_left, dirpath));
98351898Smckusick 		else if (cmp < 0)
98451898Smckusick 			return (dirp_search(dp->dp_right, dirpath));
98551898Smckusick 		else
98651898Smckusick 			return (dp);
98751898Smckusick 	}
98851898Smckusick 	return (dp);
98951898Smckusick }
99051898Smckusick 
99151898Smckusick /*
99251898Smckusick  * Scan for a host match in a directory tree.
99351898Smckusick  */
99451898Smckusick chk_host(dp, saddr, defsetp)
99551898Smckusick 	struct dirlist *dp;
99651898Smckusick 	u_long saddr;
99751898Smckusick 	int *defsetp;
99851898Smckusick {
99951898Smckusick 	register struct hostlist *hp;
100051898Smckusick 	register struct grouplist *grp;
100151898Smckusick 	register u_long **addrp;
100251898Smckusick 
100351898Smckusick 	if (dp) {
100451898Smckusick 		if (dp->dp_flag & DP_DEFSET)
100551898Smckusick 			*defsetp = 1;
100651898Smckusick 		hp = dp->dp_hosts;
100751898Smckusick 		while (hp) {
100851898Smckusick 			grp = hp->ht_grp;
100951898Smckusick 			switch (grp->gr_type) {
101051898Smckusick 			case GT_HOST:
101151898Smckusick 			    addrp = (u_long **)
101251898Smckusick 				grp->gr_ptr.gt_hostent->h_addr_list;
101351898Smckusick 			    while (*addrp) {
101451898Smckusick 				if (**addrp == saddr)
101551898Smckusick 				    return (1);
101651898Smckusick 				addrp++;
101751898Smckusick 			    }
101851898Smckusick 			    break;
101951898Smckusick 			case GT_NET:
102051898Smckusick 			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
102151898Smckusick 				grp->gr_ptr.gt_net.nt_net)
102251898Smckusick 				return (1);
102351898Smckusick 			    break;
102451898Smckusick 			};
102551898Smckusick 			hp = hp->ht_next;
102651898Smckusick 		}
102751898Smckusick 	}
102851898Smckusick 	return (0);
102951898Smckusick }
103051898Smckusick 
103151898Smckusick /*
103251898Smckusick  * Scan tree for a host that matches the address.
103351898Smckusick  */
103451898Smckusick scan_tree(dp, saddr)
103551898Smckusick 	register struct dirlist *dp;
103651898Smckusick 	u_long saddr;
103751898Smckusick {
103851898Smckusick 	int defset;
103951898Smckusick 
104051898Smckusick 	if (dp) {
104151898Smckusick 		if (scan_tree(dp->dp_left, saddr))
104251898Smckusick 			return (1);
104351898Smckusick 		if (chk_host(dp, saddr, &defset))
104451898Smckusick 			return (1);
104551898Smckusick 		if (scan_tree(dp->dp_right, saddr))
104651898Smckusick 			return (1);
104751898Smckusick 	}
104851898Smckusick 	return (0);
104951898Smckusick }
105051898Smckusick 
105151898Smckusick /*
105251898Smckusick  * Traverse the dirlist tree and free it up.
105351898Smckusick  */
105451898Smckusick void
105551898Smckusick free_dir(dp)
105651898Smckusick 	register struct dirlist *dp;
105751898Smckusick {
105851898Smckusick 
105951898Smckusick 	if (dp) {
106051898Smckusick 		free_dir(dp->dp_left);
106151898Smckusick 		free_dir(dp->dp_right);
106251898Smckusick 		free_host(dp->dp_hosts);
106351898Smckusick 		free((caddr_t)dp);
106451898Smckusick 	}
106551898Smckusick }
106651898Smckusick 
106751898Smckusick /*
106851898Smckusick  * Parse the option string and update fields.
106951898Smckusick  * Option arguments may either be -<option>=<value> or
107051898Smckusick  * -<option> <value>
107151898Smckusick  */
107251898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
107351898Smckusick 	char **cpp, **endcpp;
107451898Smckusick 	struct exportlist *ep;
107551898Smckusick 	struct grouplist *grp;
107651898Smckusick 	int *has_hostp;
107751898Smckusick 	int *exflagsp;
107851898Smckusick 	struct ucred *cr;
107951898Smckusick {
108051898Smckusick 	register char *cpoptarg, *cpoptend;
108151898Smckusick 	char *cp, *endcp, *cpopt, savedc, savedc2;
108251898Smckusick 	int allflag, usedarg;
108351898Smckusick 
108451898Smckusick 	cpopt = *cpp;
108551898Smckusick 	cpopt++;
108651898Smckusick 	cp = *endcpp;
108751898Smckusick 	savedc = *cp;
108851898Smckusick 	*cp = '\0';
108951898Smckusick 	while (cpopt && *cpopt) {
109051898Smckusick 		allflag = 1;
109151898Smckusick 		usedarg = -2;
109251898Smckusick 		if (cpoptend = index(cpopt, ',')) {
109351898Smckusick 			*cpoptend++ = '\0';
109451898Smckusick 			if (cpoptarg = index(cpopt, '='))
109551898Smckusick 				*cpoptarg++ = '\0';
109651898Smckusick 		} else {
109751898Smckusick 			if (cpoptarg = index(cpopt, '='))
109851898Smckusick 				*cpoptarg++ = '\0';
109951898Smckusick 			else {
110051898Smckusick 				*cp = savedc;
110151898Smckusick 				nextfield(&cp, &endcp);
110251898Smckusick 				**endcpp = '\0';
110351898Smckusick 				if (endcp > cp && *cp != '-') {
110451898Smckusick 					cpoptarg = cp;
110551898Smckusick 					savedc2 = *endcp;
110651898Smckusick 					*endcp = '\0';
110751898Smckusick 					usedarg = 0;
110851667Smckusick 				}
110951667Smckusick 			}
111051667Smckusick 		}
111151898Smckusick 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
111251898Smckusick 			*exflagsp |= MNT_EXRDONLY;
111351898Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
111451898Smckusick 		    !(allflag = strcmp(cpopt, "mapall")) ||
111551898Smckusick 		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
111651898Smckusick 			usedarg++;
111751898Smckusick 			parsecred(cpoptarg, cr);
111851898Smckusick 			if (allflag == 0) {
111951898Smckusick 				*exflagsp |= MNT_EXPORTANON;
112051898Smckusick 				opt_flags |= OP_MAPALL;
112151898Smckusick 			} else
112251898Smckusick 				opt_flags |= OP_MAPROOT;
112351898Smckusick 		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
112451898Smckusick 			*exflagsp |= MNT_EXKERB;
112551898Smckusick 			opt_flags |= OP_KERB;
112653150Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
112753150Smckusick 			!strcmp(cpopt, "m"))) {
112851898Smckusick 			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
112951898Smckusick 				syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
113051898Smckusick 				return (1);
113151898Smckusick 			}
113251898Smckusick 			usedarg++;
113351898Smckusick 			opt_flags |= OP_MASK;
113453150Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
113553150Smckusick 			!strcmp(cpopt, "n"))) {
113651898Smckusick 			if (grp->gr_type != GT_NULL) {
113751898Smckusick 				syslog(LOG_ERR, "Network/host conflict");
113851898Smckusick 				return (1);
113951898Smckusick 			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
114051898Smckusick 				syslog(LOG_ERR, "Bad net: %s", cpoptarg);
114151898Smckusick 				return (1);
114251898Smckusick 			}
114351898Smckusick 			grp->gr_type = GT_NET;
114451898Smckusick 			*has_hostp = 1;
114551898Smckusick 			usedarg++;
114651898Smckusick 			opt_flags |= OP_NET;
114751898Smckusick 		} else if (!strcmp(cpopt, "alldirs")) {
114851898Smckusick 			opt_flags |= OP_ALLDIRS;
114951898Smckusick #ifdef ISO
115051898Smckusick 		} else if (cpoptarg && !strcmp(cpopt, "iso")) {
115151898Smckusick 			if (get_isoaddr(cpoptarg, grp)) {
115251898Smckusick 				syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
115351898Smckusick 				return (1);
115451898Smckusick 			}
115551898Smckusick 			*has_hostp = 1;
115651898Smckusick 			usedarg++;
115751898Smckusick 			opt_flags |= OP_ISO;
115851898Smckusick #endif /* ISO */
115951898Smckusick 		} else {
116051898Smckusick 			syslog(LOG_ERR, "Bad opt %s", cpopt);
116151898Smckusick 			return (1);
116251667Smckusick 		}
116351898Smckusick 		if (usedarg >= 0) {
116451898Smckusick 			*endcp = savedc2;
116551898Smckusick 			**endcpp = savedc;
116651898Smckusick 			if (usedarg > 0) {
116751898Smckusick 				*cpp = cp;
116851898Smckusick 				*endcpp = endcp;
116951898Smckusick 			}
117051898Smckusick 			return (0);
117151898Smckusick 		}
117251898Smckusick 		cpopt = cpoptend;
117351667Smckusick 	}
117451898Smckusick 	**endcpp = savedc;
117551898Smckusick 	return (0);
117651898Smckusick }
117751898Smckusick 
117851898Smckusick /*
117951898Smckusick  * Translate a character string to the corresponding list of network
118051898Smckusick  * addresses for a hostname.
118151898Smckusick  */
118251898Smckusick get_host(cp, grp)
118351898Smckusick 	char *cp;
118451898Smckusick 	register struct grouplist *grp;
118551898Smckusick {
118651898Smckusick 	register struct hostent *hp, *nhp;
118751898Smckusick 	register char **addrp, **naddrp;
118851898Smckusick 	struct hostent t_host;
118951898Smckusick 	int i;
119051898Smckusick 	u_long saddr;
119151898Smckusick 	char *aptr[2];
119251898Smckusick 
119351898Smckusick 	if (grp->gr_type != GT_NULL)
119451898Smckusick 		return (1);
119551898Smckusick 	if ((hp = gethostbyname(cp)) == NULL) {
119651898Smckusick 		if (isdigit(*cp)) {
119751898Smckusick 			saddr = inet_addr(cp);
119851898Smckusick 			if (saddr == -1) {
119951898Smckusick 				syslog(LOG_ERR, "Inet_addr failed");
120051898Smckusick 				return (1);
120151898Smckusick 			}
120251898Smckusick 			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
120351898Smckusick 				AF_INET)) == NULL) {
120451898Smckusick 				hp = &t_host;
120551898Smckusick 				hp->h_name = cp;
120651898Smckusick 				hp->h_addrtype = AF_INET;
120751898Smckusick 				hp->h_length = sizeof (u_long);
120851898Smckusick 				hp->h_addr_list = aptr;
120951898Smckusick 				aptr[0] = (char *)&saddr;
121051898Smckusick 				aptr[1] = (char *)0;
121151898Smckusick 			}
121251898Smckusick 		} else {
121351898Smckusick 			syslog(LOG_ERR, "Gethostbyname failed");
121451898Smckusick 			return (1);
121551898Smckusick 		}
121651898Smckusick 	}
121751898Smckusick 	grp->gr_type = GT_HOST;
121851898Smckusick 	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
121951898Smckusick 		malloc(sizeof(struct hostent));
122051898Smckusick 	if (nhp == (struct hostent *)0)
122151898Smckusick 		out_of_mem();
122251898Smckusick 	bcopy((caddr_t)hp, (caddr_t)nhp,
122351898Smckusick 		sizeof(struct hostent));
122451898Smckusick 	i = strlen(hp->h_name)+1;
122551898Smckusick 	nhp->h_name = (char *)malloc(i);
122651898Smckusick 	if (nhp->h_name == (char *)0)
122751898Smckusick 		out_of_mem();
122851898Smckusick 	bcopy(hp->h_name, nhp->h_name, i);
122951898Smckusick 	addrp = hp->h_addr_list;
123051898Smckusick 	i = 1;
123151898Smckusick 	while (*addrp++)
123251898Smckusick 		i++;
123351898Smckusick 	naddrp = nhp->h_addr_list = (char **)
123451898Smckusick 		malloc(i*sizeof(char *));
123551898Smckusick 	if (naddrp == (char **)0)
123651898Smckusick 		out_of_mem();
123751898Smckusick 	addrp = hp->h_addr_list;
123851898Smckusick 	while (*addrp) {
123951898Smckusick 		*naddrp = (char *)
124051898Smckusick 		    malloc(hp->h_length);
124151898Smckusick 		if (*naddrp == (char *)0)
124251898Smckusick 		    out_of_mem();
124351898Smckusick 		bcopy(*addrp, *naddrp,
124451898Smckusick 			hp->h_length);
124551898Smckusick 		addrp++;
124651898Smckusick 		naddrp++;
124751898Smckusick 	}
124851898Smckusick 	*naddrp = (char *)0;
124953150Smckusick 	if (debug)
125053150Smckusick 		fprintf(stderr, "got host %s\n", hp->h_name);
125151898Smckusick 	return (0);
125251898Smckusick }
125351898Smckusick 
125451898Smckusick /*
125551898Smckusick  * Free up an exports list component
125651898Smckusick  */
125751898Smckusick void
125851898Smckusick free_exp(ep)
125951898Smckusick 	register struct exportlist *ep;
126051898Smckusick {
126151898Smckusick 
126251898Smckusick 	if (ep->ex_defdir) {
126351898Smckusick 		free_host(ep->ex_defdir->dp_hosts);
126451898Smckusick 		free((caddr_t)ep->ex_defdir);
126551898Smckusick 	}
126651898Smckusick 	if (ep->ex_fsdir)
126751898Smckusick 		free(ep->ex_fsdir);
126851898Smckusick 	free_dir(ep->ex_dirl);
126951898Smckusick 	free((caddr_t)ep);
127051898Smckusick }
127151898Smckusick 
127251898Smckusick /*
127351898Smckusick  * Free hosts.
127451898Smckusick  */
127551898Smckusick void
127651898Smckusick free_host(hp)
127751898Smckusick 	register struct hostlist *hp;
127851898Smckusick {
127951898Smckusick 	register struct hostlist *hp2;
128051898Smckusick 
128151898Smckusick 	while (hp) {
128251898Smckusick 		hp2 = hp;
128351898Smckusick 		hp = hp->ht_next;
128451898Smckusick 		free((caddr_t)hp2);
128551898Smckusick 	}
128651898Smckusick }
128751898Smckusick 
128851898Smckusick struct hostlist *
128951898Smckusick get_ht()
129051898Smckusick {
129151898Smckusick 	register struct hostlist *hp;
129251898Smckusick 
129351898Smckusick 	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
129451898Smckusick 	if (hp == (struct hostlist *)0)
129551898Smckusick 		out_of_mem();
129651898Smckusick 	hp->ht_next = (struct hostlist *)0;
129751898Smckusick 	return (hp);
129851898Smckusick }
129951898Smckusick 
130051898Smckusick #ifdef ISO
130151898Smckusick /*
130251898Smckusick  * Translate an iso address.
130351898Smckusick  */
130451898Smckusick get_isoaddr(cp, grp)
130551898Smckusick 	char *cp;
130651898Smckusick 	struct grouplist *grp;
130751898Smckusick {
130851898Smckusick 	struct iso_addr *isop;
130951898Smckusick 	struct sockaddr_iso *isoaddr;
131051898Smckusick 
131151898Smckusick 	if (grp->gr_type != GT_NULL)
131251898Smckusick 		return (1);
131351898Smckusick 	if ((isop = iso_addr(cp)) == NULL) {
131451898Smckusick 		syslog(LOG_ERR,
131551898Smckusick 		    "iso_addr failed, ignored");
131651898Smckusick 		return (1);
131751898Smckusick 	}
131851898Smckusick 	isoaddr = (struct sockaddr_iso *)
131951898Smckusick 	    malloc(sizeof (struct sockaddr_iso));
132051898Smckusick 	if (isoaddr == (struct sockaddr_iso *)0)
132151898Smckusick 		out_of_mem();
132251898Smckusick 	bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
132351898Smckusick 	bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr,
132451898Smckusick 		sizeof (struct iso_addr));
132551898Smckusick 	isoaddr->siso_len = sizeof (struct sockaddr_iso);
132651898Smckusick 	isoaddr->siso_family = AF_ISO;
132751898Smckusick 	grp->gr_type = GT_ISO;
132851898Smckusick 	grp->gr_ptr.gt_isoaddr = isoaddr;
132951898Smckusick 	return (0);
133051898Smckusick }
133151898Smckusick #endif	/* ISO */
133251898Smckusick 
133351898Smckusick /*
133451898Smckusick  * Out of memory, fatal
133551898Smckusick  */
133651898Smckusick void
133751898Smckusick out_of_mem()
133851898Smckusick {
133951898Smckusick 
134051898Smckusick 	syslog(LOG_ERR, "Out of memory");
134151667Smckusick 	exit(2);
134251667Smckusick }
134351667Smckusick 
134451898Smckusick /*
134551898Smckusick  * Do the mount syscall with the update flag to push the export info into
134651898Smckusick  * the kernel.
134751898Smckusick  */
134851898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
134951667Smckusick 	struct exportlist *ep;
135051667Smckusick 	struct grouplist *grp;
135151898Smckusick 	int exflags;
135251667Smckusick 	struct ucred *anoncrp;
135351898Smckusick 	char *dirp;
135451898Smckusick 	int dirplen;
135551898Smckusick 	struct statfs *fsb;
135651667Smckusick {
135751898Smckusick 	register char *cp = (char *)0;
135851667Smckusick 	register u_long **addrp;
135951898Smckusick 	int done;
136051898Smckusick 	char savedc;
136151898Smckusick 	struct sockaddr_in sin, imask;
136252109Smckusick 	struct ufs_args args;
136351898Smckusick 	u_long net;
136451667Smckusick 
136551667Smckusick 	args.fspec = 0;
136651667Smckusick 	args.exflags = exflags;
136751667Smckusick 	args.anon = *anoncrp;
136851667Smckusick 	sin.sin_family = AF_INET;
136951667Smckusick 	sin.sin_port = 0;
137051667Smckusick 	sin.sin_len = sizeof(sin);
137151898Smckusick 	imask.sin_family = AF_INET;
137251898Smckusick 	imask.sin_port = 0;
137351898Smckusick 	imask.sin_len = sizeof(sin);
137451898Smckusick 	if (grp->gr_type == GT_HOST)
137551667Smckusick 		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
137651898Smckusick 	else
137751898Smckusick 		addrp = (u_long **)0;
137851667Smckusick 	done = FALSE;
137951898Smckusick 	while (!done) {
138051898Smckusick 		switch (grp->gr_type) {
138151898Smckusick 		case GT_HOST:
138251898Smckusick 			if (addrp)
138351712Smckusick 				sin.sin_addr.s_addr = **addrp;
138451712Smckusick 			else
138551667Smckusick 				sin.sin_addr.s_addr = INADDR_ANY;
138651667Smckusick 			args.saddr = (struct sockaddr *)&sin;
138751667Smckusick 			args.slen = sizeof(sin);
138851898Smckusick 			args.msklen = 0;
138951898Smckusick 			break;
139051898Smckusick 		case GT_NET:
139151898Smckusick 			if (grp->gr_ptr.gt_net.nt_mask)
139251898Smckusick 			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
139351898Smckusick 			else {
139451898Smckusick 			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
139551898Smckusick 			    if (IN_CLASSA(net))
139651898Smckusick 				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
139751898Smckusick 			    else if (IN_CLASSB(net))
139851898Smckusick 				imask.sin_addr.s_addr =
139951898Smckusick 				    inet_addr("255.255.0.0");
140051898Smckusick 			    else
140151898Smckusick 				imask.sin_addr.s_addr =
140251898Smckusick 				    inet_addr("255.255.255.0");
140351898Smckusick 			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
140451898Smckusick 			}
140551898Smckusick 			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
140651898Smckusick 			args.saddr = (struct sockaddr *)&sin;
140751898Smckusick 			args.slen = sizeof (sin);
140851898Smckusick 			args.smask = (struct sockaddr *)&imask;
140951898Smckusick 			args.msklen = sizeof (imask);
141051898Smckusick 			break;
141151667Smckusick #ifdef ISO
141251898Smckusick 		case GT_ISO:
141351667Smckusick 			args.saddr = (struct sockaddr *)grp->gr_ptr.gt_isoaddr;
141451667Smckusick 			args.slen = sizeof (struct sockaddr_iso);
141551898Smckusick 			args.msklen = 0;
141651898Smckusick 			break;
141751667Smckusick #endif	/* ISO */
141851898Smckusick 		default:
141951667Smckusick 			syslog(LOG_ERR, "Bad grouptype");
142051898Smckusick 			if (cp)
142151898Smckusick 				*cp = savedc;
142251898Smckusick 			return (1);
142351898Smckusick 		};
142452109Smckusick 
142552109Smckusick 		/*
142652109Smckusick 		 * XXX:
142752109Smckusick 		 * Maybe I should just use the fsb->f_mntonname path instead
142852109Smckusick 		 * of looping back up the dirp to the mount point??
142952109Smckusick 		 * Also, needs to know how to export all types of local
143052109Smckusick 		 * exportable file systems and not just MOUNT_UFS.
143152109Smckusick 		 */
143252109Smckusick 		while (mount(fsb->f_type, dirp,
143352109Smckusick 		       fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
143451898Smckusick 			if (cp)
143551898Smckusick 				*cp-- = savedc;
143651898Smckusick 			else
143751898Smckusick 				cp = dirp + dirplen - 1;
143851667Smckusick 			if (errno == EPERM) {
143951667Smckusick 				syslog(LOG_ERR,
144051898Smckusick 				   "Can't change attributes for %s.\n", dirp);
144151898Smckusick 				return (1);
144251667Smckusick 			}
144351898Smckusick 			if (opt_flags & OP_ALLDIRS) {
144451898Smckusick 				syslog(LOG_ERR, "Not root dir");
144551898Smckusick 				return (1);
144651898Smckusick 			}
144751667Smckusick 			/* back up over the last component */
144851898Smckusick 			while (*cp == '/' && cp > dirp)
144951667Smckusick 				cp--;
145051898Smckusick 			while (*(cp - 1) != '/' && cp > dirp)
145151667Smckusick 				cp--;
145251898Smckusick 			if (cp == dirp) {
145351898Smckusick 				if (debug)
145451667Smckusick 					fprintf(stderr,"mnt unsucc\n");
145551898Smckusick 				syslog(LOG_ERR, "Can't export %s", dirp);
145651898Smckusick 				return (1);
145751667Smckusick 			}
145851667Smckusick 			savedc = *cp;
145951667Smckusick 			*cp = '\0';
146051667Smckusick 		}
146151898Smckusick 		if (addrp) {
146251667Smckusick 			++addrp;
146351898Smckusick 			if (*addrp == (u_long *)0)
146451667Smckusick 				done = TRUE;
146551898Smckusick 		} else
146651898Smckusick 			done = TRUE;
146751898Smckusick 	}
146851898Smckusick 	if (cp)
146951898Smckusick 		*cp = savedc;
147051898Smckusick 	return (0);
147151898Smckusick }
147251898Smckusick 
147351898Smckusick /*
147451898Smckusick  * Translate a net address.
147551898Smckusick  */
147651898Smckusick get_net(cp, net, maskflg)
147751898Smckusick 	char *cp;
147851898Smckusick 	struct netmsk *net;
147951898Smckusick 	int maskflg;
148051898Smckusick {
148151898Smckusick 	register struct netent *np;
148251898Smckusick 	register long netaddr;
148351898Smckusick 	struct in_addr inetaddr, inetaddr2;
148451898Smckusick 	char *name;
148551898Smckusick 
148651898Smckusick 	if (np = getnetbyname(cp))
148751898Smckusick 		inetaddr = inet_makeaddr(np->n_net, 0);
148851898Smckusick 	else if (isdigit(*cp)) {
148951898Smckusick 		if ((netaddr = inet_network(cp)) == -1)
149051898Smckusick 			return (1);
149151898Smckusick 		inetaddr = inet_makeaddr(netaddr, 0);
149251898Smckusick 		/*
149351898Smckusick 		 * Due to arbritrary subnet masks, you don't know how many
149451898Smckusick 		 * bits to shift the address to make it into a network,
149551898Smckusick 		 * however you do know how to make a network address into
149651898Smckusick 		 * a host with host == 0 and then compare them.
149751898Smckusick 		 * (What a pest)
149851898Smckusick 		 */
149951898Smckusick 		if (!maskflg) {
150051898Smckusick 			setnetent(0);
150151898Smckusick 			while (np = getnetent()) {
150251898Smckusick 				inetaddr2 = inet_makeaddr(np->n_net, 0);
150351898Smckusick 				if (inetaddr2.s_addr == inetaddr.s_addr)
150451898Smckusick 					break;
150551898Smckusick 			}
150651898Smckusick 			endnetent();
150751667Smckusick 		}
150851898Smckusick 	} else
150951898Smckusick 		return (1);
151051898Smckusick 	if (maskflg)
151151898Smckusick 		net->nt_mask = inetaddr.s_addr;
151251898Smckusick 	else {
151351898Smckusick 		if (np)
151451898Smckusick 			name = np->n_name;
151551898Smckusick 		else
151651898Smckusick 			name = inet_ntoa(inetaddr);
151751898Smckusick 		net->nt_name = (char *)malloc(strlen(name) + 1);
151851898Smckusick 		if (net->nt_name == (char *)0)
151951898Smckusick 			out_of_mem();
152051898Smckusick 		strcpy(net->nt_name, name);
152151898Smckusick 		net->nt_net = inetaddr.s_addr;
152238460Smckusick 	}
152351898Smckusick 	return (0);
152438460Smckusick }
152538460Smckusick 
152638460Smckusick /*
152738460Smckusick  * Parse out the next white space separated field
152838460Smckusick  */
152951667Smckusick void
153038460Smckusick nextfield(cp, endcp)
153138460Smckusick 	char **cp;
153238460Smckusick 	char **endcp;
153338460Smckusick {
153438460Smckusick 	register char *p;
153538460Smckusick 
153638460Smckusick 	p = *cp;
153738460Smckusick 	while (*p == ' ' || *p == '\t')
153838460Smckusick 		p++;
153951898Smckusick 	if (*p == '\n' || *p == '\0')
154038460Smckusick 		*cp = *endcp = p;
154151898Smckusick 	else {
154251898Smckusick 		*cp = p++;
154351898Smckusick 		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
154451898Smckusick 			p++;
154551898Smckusick 		*endcp = p;
154638460Smckusick 	}
154738460Smckusick }
154839681Smckusick 
154939681Smckusick /*
155051898Smckusick  * Get an exports file line. Skip over blank lines and handle line
155151898Smckusick  * continuations.
155239681Smckusick  */
155351898Smckusick get_line()
155439681Smckusick {
155551898Smckusick 	register char *p, *cp;
155651898Smckusick 	register int len;
155751898Smckusick 	int totlen, cont_line;
155839681Smckusick 
155951898Smckusick 	/*
156051898Smckusick 	 * Loop around ignoring blank lines and getting all continuation lines.
156151898Smckusick 	 */
156251898Smckusick 	p = line;
156351898Smckusick 	totlen = 0;
156451898Smckusick 	do {
156551898Smckusick 		if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
156651898Smckusick 			return (0);
156751898Smckusick 		len = strlen(p);
156851898Smckusick 		cp = p + len - 1;
156951898Smckusick 		cont_line = 0;
157051898Smckusick 		while (cp >= p &&
157151898Smckusick 		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
157251898Smckusick 			if (*cp == '\\')
157351898Smckusick 				cont_line = 1;
157451898Smckusick 			cp--;
157551898Smckusick 			len--;
157651898Smckusick 		}
157751898Smckusick 		*++cp = '\0';
157851898Smckusick 		if (len > 0) {
157951898Smckusick 			totlen += len;
158051898Smckusick 			if (totlen >= LINESIZ) {
158151898Smckusick 				syslog(LOG_ERR, "Exports line too long");
158251898Smckusick 				exit(2);
158351898Smckusick 			}
158451898Smckusick 			p = cp;
158551898Smckusick 		}
158651898Smckusick 	} while (totlen == 0 || cont_line);
158751898Smckusick 	return (1);
158844015Smckusick }
158944015Smckusick 
159051667Smckusick /*
159151667Smckusick  * Parse a description of a credential.
159251667Smckusick  */
159351667Smckusick parsecred(namelist, cr)
159451667Smckusick 	char *namelist;
159551667Smckusick 	register struct ucred *cr;
159651667Smckusick {
159751667Smckusick 	register char *name;
159851667Smckusick 	register int cnt;
159951667Smckusick 	char *names;
160051667Smckusick 	struct passwd *pw;
160151667Smckusick 	struct group *gr;
160251667Smckusick 	int ngroups, groups[NGROUPS + 1];
160351667Smckusick 
160451667Smckusick 	/*
160551667Smckusick 	 * Set up the unpriviledged user.
160651667Smckusick 	 */
160751667Smckusick 	cr->cr_ref = 1;
160851667Smckusick 	cr->cr_uid = -2;
160951667Smckusick 	cr->cr_groups[0] = -2;
161051667Smckusick 	cr->cr_ngroups = 1;
161151667Smckusick 	/*
161251667Smckusick 	 * Get the user's password table entry.
161351667Smckusick 	 */
161451667Smckusick 	names = strsep(&namelist, " \t\n");
161551667Smckusick 	name = strsep(&names, ":");
161651667Smckusick 	if (isdigit(*name) || *name == '-')
161751667Smckusick 		pw = getpwuid(atoi(name));
161851667Smckusick 	else
161951667Smckusick 		pw = getpwnam(name);
162051667Smckusick 	/*
162151667Smckusick 	 * Credentials specified as those of a user.
162251667Smckusick 	 */
162351667Smckusick 	if (names == NULL) {
162451667Smckusick 		if (pw == NULL) {
162551667Smckusick 			syslog(LOG_ERR, "Unknown user: %s\n", name);
162651667Smckusick 			return;
162751667Smckusick 		}
162851667Smckusick 		cr->cr_uid = pw->pw_uid;
162951667Smckusick 		ngroups = NGROUPS + 1;
163051667Smckusick 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
163151667Smckusick 			syslog(LOG_ERR, "Too many groups\n");
163251667Smckusick 		/*
163351667Smckusick 		 * Convert from int's to gid_t's and compress out duplicate
163451667Smckusick 		 */
163551667Smckusick 		cr->cr_ngroups = ngroups - 1;
163651667Smckusick 		cr->cr_groups[0] = groups[0];
163751667Smckusick 		for (cnt = 2; cnt < ngroups; cnt++)
163851667Smckusick 			cr->cr_groups[cnt - 1] = groups[cnt];
163951667Smckusick 		return;
164051667Smckusick 	}
164151667Smckusick 	/*
164251667Smckusick 	 * Explicit credential specified as a colon separated list:
164351667Smckusick 	 *	uid:gid:gid:...
164451667Smckusick 	 */
164551667Smckusick 	if (pw != NULL)
164651667Smckusick 		cr->cr_uid = pw->pw_uid;
164751667Smckusick 	else if (isdigit(*name) || *name == '-')
164851667Smckusick 		cr->cr_uid = atoi(name);
164951667Smckusick 	else {
165051667Smckusick 		syslog(LOG_ERR, "Unknown user: %s\n", name);
165151667Smckusick 		return;
165251667Smckusick 	}
165351667Smckusick 	cr->cr_ngroups = 0;
165451667Smckusick 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
165551667Smckusick 		name = strsep(&names, ":");
165651667Smckusick 		if (isdigit(*name) || *name == '-') {
165751667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
165851667Smckusick 		} else {
165951667Smckusick 			if ((gr = getgrnam(name)) == NULL) {
166051667Smckusick 				syslog(LOG_ERR, "Unknown group: %s\n", name);
166151667Smckusick 				continue;
166251667Smckusick 			}
166351667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
166451667Smckusick 		}
166551667Smckusick 	}
166651667Smckusick 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
166751667Smckusick 		syslog(LOG_ERR, "Too many groups\n");
166851667Smckusick }
166951667Smckusick 
167044015Smckusick #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
167144015Smckusick /*
167244015Smckusick  * Routines that maintain the remote mounttab
167344015Smckusick  */
167451667Smckusick void
167551667Smckusick get_mountlist()
167644015Smckusick {
167744015Smckusick 	register struct mountlist *mlp, **mlpp;
167844015Smckusick 	register char *eos, *dirp;
167944015Smckusick 	int len;
168044015Smckusick 	char str[STRSIZ];
168144015Smckusick 	FILE *mlfile;
168244015Smckusick 
168351712Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
168451667Smckusick 		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
168544015Smckusick 		return;
168644015Smckusick 	}
168744015Smckusick 	mlpp = &mlhead;
168844015Smckusick 	while (fgets(str, STRSIZ, mlfile) != NULL) {
168944015Smckusick 		if ((dirp = index(str, '\t')) == NULL &&
169044015Smckusick 		    (dirp = index(str, ' ')) == NULL)
169144015Smckusick 			continue;
169244015Smckusick 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
169344015Smckusick 		len = dirp-str;
169444015Smckusick 		if (len > RPCMNT_NAMELEN)
169544015Smckusick 			len = RPCMNT_NAMELEN;
169644015Smckusick 		bcopy(str, mlp->ml_host, len);
169744015Smckusick 		mlp->ml_host[len] = '\0';
169844015Smckusick 		while (*dirp == '\t' || *dirp == ' ')
169944015Smckusick 			dirp++;
170044015Smckusick 		if ((eos = index(dirp, '\t')) == NULL &&
170144015Smckusick 		    (eos = index(dirp, ' ')) == NULL &&
170244015Smckusick 		    (eos = index(dirp, '\n')) == NULL)
170344015Smckusick 			len = strlen(dirp);
170444015Smckusick 		else
170544015Smckusick 			len = eos-dirp;
170644015Smckusick 		if (len > RPCMNT_PATHLEN)
170744015Smckusick 			len = RPCMNT_PATHLEN;
170844015Smckusick 		bcopy(dirp, mlp->ml_dirp, len);
170944015Smckusick 		mlp->ml_dirp[len] = '\0';
171044015Smckusick 		mlp->ml_next = (struct mountlist *)0;
171144015Smckusick 		*mlpp = mlp;
171244015Smckusick 		mlpp = &mlp->ml_next;
171344015Smckusick 	}
171444015Smckusick 	fclose(mlfile);
171544015Smckusick }
171644015Smckusick 
171751667Smckusick void
171851667Smckusick del_mlist(hostp, dirp)
171944015Smckusick 	register char *hostp, *dirp;
172044015Smckusick {
172144015Smckusick 	register struct mountlist *mlp, **mlpp;
172251712Smckusick 	struct mountlist *mlp2;
172344015Smckusick 	FILE *mlfile;
172444015Smckusick 	int fnd = 0;
172544015Smckusick 
172644015Smckusick 	mlpp = &mlhead;
172744015Smckusick 	mlp = mlhead;
172844015Smckusick 	while (mlp) {
172944015Smckusick 		if (!strcmp(mlp->ml_host, hostp) &&
173044015Smckusick 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
173144015Smckusick 			fnd = 1;
173251712Smckusick 			mlp2 = mlp;
173351712Smckusick 			*mlpp = mlp = mlp->ml_next;
173451712Smckusick 			free((caddr_t)mlp2);
173551712Smckusick 		} else {
173651712Smckusick 			mlpp = &mlp->ml_next;
173751712Smckusick 			mlp = mlp->ml_next;
173839681Smckusick 		}
173939681Smckusick 	}
174044015Smckusick 	if (fnd) {
174144015Smckusick 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
174251898Smckusick 			syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
174344015Smckusick 			return;
174444015Smckusick 		}
174544015Smckusick 		mlp = mlhead;
174644015Smckusick 		while (mlp) {
174744015Smckusick 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
174844015Smckusick 			mlp = mlp->ml_next;
174944015Smckusick 		}
175044015Smckusick 		fclose(mlfile);
175144015Smckusick 	}
175239681Smckusick }
175344015Smckusick 
175451667Smckusick void
175551667Smckusick add_mlist(hostp, dirp)
175644015Smckusick 	register char *hostp, *dirp;
175744015Smckusick {
175844015Smckusick 	register struct mountlist *mlp, **mlpp;
175944015Smckusick 	FILE *mlfile;
176044015Smckusick 
176144015Smckusick 	mlpp = &mlhead;
176244015Smckusick 	mlp = mlhead;
176344015Smckusick 	while (mlp) {
176444015Smckusick 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
176544015Smckusick 			return;
176644015Smckusick 		mlpp = &mlp->ml_next;
176744015Smckusick 		mlp = mlp->ml_next;
176844015Smckusick 	}
176944015Smckusick 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
177044015Smckusick 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
177144015Smckusick 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
177244015Smckusick 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
177344015Smckusick 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
177444015Smckusick 	mlp->ml_next = (struct mountlist *)0;
177544015Smckusick 	*mlpp = mlp;
177644015Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
177751898Smckusick 		syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
177844015Smckusick 		return;
177944015Smckusick 	}
178044015Smckusick 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
178144015Smckusick 	fclose(mlfile);
178244015Smckusick }
178344015Smckusick 
178444015Smckusick /*
178544015Smckusick  * This function is called via. SIGTERM when the system is going down.
178644015Smckusick  * It sends a broadcast RPCMNT_UMNTALL.
178744015Smckusick  */
178846709Sbostic void
178944015Smckusick send_umntall()
179044015Smckusick {
179144015Smckusick 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
179244015Smckusick 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
179351667Smckusick 	exit(0);
179444015Smckusick }
179544015Smckusick 
179644015Smckusick umntall_each(resultsp, raddr)
179744015Smckusick 	caddr_t resultsp;
179844015Smckusick 	struct sockaddr_in *raddr;
179944015Smckusick {
180044015Smckusick 	return (1);
180144015Smckusick }
180244015Smckusick 
180344015Smckusick /*
180451667Smckusick  * Free up a group list.
180551667Smckusick  */
180651667Smckusick void
180751667Smckusick free_grp(grp)
180851667Smckusick 	register struct grouplist *grp;
180951667Smckusick {
181051667Smckusick 	register char **addrp;
181151667Smckusick 
181251898Smckusick 	if (grp->gr_type == GT_HOST) {
181351712Smckusick 		if (grp->gr_ptr.gt_hostent->h_name) {
181451712Smckusick 			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
181551712Smckusick 			while (addrp && *addrp)
181651712Smckusick 				free(*addrp++);
181751712Smckusick 			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
181851712Smckusick 			free(grp->gr_ptr.gt_hostent->h_name);
181951712Smckusick 		}
182051667Smckusick 		free((caddr_t)grp->gr_ptr.gt_hostent);
182151898Smckusick 	} else if (grp->gr_type == GT_NET) {
182251898Smckusick 		if (grp->gr_ptr.gt_net.nt_name)
182351898Smckusick 			free(grp->gr_ptr.gt_net.nt_name);
182451667Smckusick 	}
182551667Smckusick #ifdef ISO
182651898Smckusick 	else if (grp->gr_type == GT_ISO)
182751667Smckusick 		free((caddr_t)grp->gr_ptr.gt_isoaddr);
182851667Smckusick #endif
182951667Smckusick 	free((caddr_t)grp);
183051667Smckusick }
183151667Smckusick 
183251667Smckusick /*
183351667Smckusick  * char *realpath(const char *path, char resolved_path[MAXPATHLEN])
183451667Smckusick  *
183551667Smckusick  * find the real name of path, by removing all ".", ".."
183651667Smckusick  * and symlink components.
183751667Smckusick  *
183851667Smckusick  * Jan-Simon Pendry, September 1991.
183951667Smckusick  */
184051667Smckusick char *
184151667Smckusick realpath(path, resolved)
184251667Smckusick 	char *path;
184351667Smckusick 	char resolved[MAXPATHLEN];
184451667Smckusick {
184551667Smckusick 	int d = open(".", O_RDONLY);
184651667Smckusick 	int rootd = 0;
184751667Smckusick 	char *p, *q;
184851667Smckusick 	struct stat stb;
184951667Smckusick 	char wbuf[MAXPATHLEN];
185051667Smckusick 
185151667Smckusick 	strcpy(resolved, path);
185251667Smckusick 
185351667Smckusick 	if (d < 0)
185451667Smckusick 		return 0;
185551667Smckusick 
185651667Smckusick loop:;
185751667Smckusick 	q = strrchr(resolved, '/');
185851667Smckusick 	if (q) {
185951667Smckusick 		p = q + 1;
186051667Smckusick 		if (q == resolved)
186151667Smckusick 			q = "/";
186251667Smckusick 		else {
186351667Smckusick 			do
186451667Smckusick 				--q;
186551667Smckusick 			while (q > resolved && *q == '/');
186651667Smckusick 			q[1] = '\0';
186751667Smckusick 			q = resolved;
186851667Smckusick 		}
186951667Smckusick 		if (chdir(q) < 0)
187051667Smckusick 			goto out;
187151667Smckusick 	} else
187251667Smckusick 		p = resolved;
187351667Smckusick 
187451667Smckusick 	if (lstat(p, &stb) == 0) {
187551667Smckusick 		if (S_ISLNK(stb.st_mode)) {
187651667Smckusick 			int n = readlink(p, resolved, MAXPATHLEN);
187751667Smckusick 			if (n < 0)
187851667Smckusick 				goto out;
187951667Smckusick 			resolved[n] = '\0';
188051667Smckusick 			goto loop;
188151667Smckusick 		}
188251667Smckusick 		if (S_ISDIR(stb.st_mode)) {
188351667Smckusick 			if (chdir(p) < 0)
188451667Smckusick 				goto out;
188551667Smckusick 			p = "";
188651667Smckusick 		}
188751667Smckusick 	}
188851667Smckusick 
188951667Smckusick 	strcpy(wbuf, p);
189051667Smckusick 	if (getcwd(resolved, MAXPATHLEN) == 0)
189151667Smckusick 		goto out;
189251667Smckusick 	if (resolved[0] == '/' && resolved[1] == '\0')
189351667Smckusick 		rootd = 1;
189451667Smckusick 
189551667Smckusick 	if (*wbuf) {
189651667Smckusick 		if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) {
189751667Smckusick 			errno = ENAMETOOLONG;
189851667Smckusick 			goto out;
189951667Smckusick 		}
190051667Smckusick 		if (rootd == 0)
190151667Smckusick 			strcat(resolved, "/");
190251667Smckusick 		strcat(resolved, wbuf);
190351667Smckusick 	}
190451667Smckusick 
190551667Smckusick 	if (fchdir(d) < 0)
190651667Smckusick 		goto out;
190751667Smckusick 	(void) close(d);
190851667Smckusick 
190951667Smckusick 	return resolved;
191051667Smckusick 
191151667Smckusick out:;
191251667Smckusick 	(void) close(d);
191351667Smckusick 	return 0;
191451667Smckusick }
191551711Smckusick 
191651711Smckusick #ifdef DEBUG
191751711Smckusick void
191851711Smckusick SYSLOG(int pri, const char *fmt, ...)
191951711Smckusick {
192051711Smckusick 	va_list ap;
192151711Smckusick 
192251711Smckusick 	va_start(ap, fmt);
192351711Smckusick 	vfprintf(stderr, fmt, ap);
192451711Smckusick 	va_end(ap);
192551711Smckusick }
192651711Smckusick #endif /* DEBUG */
192751898Smckusick 
192851898Smckusick /*
192951898Smckusick  * Check options for consistency.
193051898Smckusick  */
193151898Smckusick check_options(dp)
193251898Smckusick 	struct dirlist *dp;
193351898Smckusick {
193451898Smckusick 
193551898Smckusick 	if (dp == (struct dirlist *)0)
193651898Smckusick 	    return (1);
193751898Smckusick 	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
193851898Smckusick 	    (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
193951898Smckusick 	    (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
194051898Smckusick 	    syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
194151898Smckusick 	    return (1);
194251898Smckusick 	}
194351898Smckusick 	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
194451898Smckusick 	    syslog(LOG_ERR, "-mask requires -net");
194551898Smckusick 	    return (1);
194651898Smckusick 	}
194751898Smckusick 	if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
194851898Smckusick 	    syslog(LOG_ERR, "-net and -iso mutually exclusive");
194951898Smckusick 	    return (1);
195051898Smckusick 	}
195151898Smckusick 	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
195251898Smckusick 	    syslog(LOG_ERR, "-alldir has multiple directories");
195351898Smckusick 	    return (1);
195451898Smckusick 	}
195551898Smckusick 	return (0);
195651898Smckusick }
1957