xref: /csrg-svn/sbin/mountd/mountd.c (revision 64903)
138460Smckusick /*
261519Sbostic  * Copyright (c) 1989, 1993
361519Sbostic  *	The Regents of the University of California.  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
1261519Sbostic static char copyright[] =
1361519Sbostic "@(#) Copyright (c) 1989, 1993\n\
1461519Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1538460Smckusick #endif not lint
1638460Smckusick 
1738460Smckusick #ifndef lint
18*64903Smckusick static char sccsid[] = "@(#)mountd.c	8.2 (Berkeley) 11/16/93";
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;
432*64903Smckusick 	int omask, putdef;
43338460Smckusick 
43438460Smckusick 	omask = sigblock(sigmask(SIGHUP));
43551898Smckusick 	ep = exphead;
43651898Smckusick 	while (ep) {
437*64903Smckusick 		putdef = 0;
438*64903Smckusick 		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef))
43938460Smckusick 			goto errout;
440*64903Smckusick 		if (ep->ex_defdir && putdef == 0 &&
441*64903Smckusick 			put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)0,
442*64903Smckusick 			&putdef))
443*64903Smckusick 			goto errout;
44438460Smckusick 		ep = ep->ex_next;
44538460Smckusick 	}
44638460Smckusick 	sigsetmask(omask);
44738460Smckusick 	if (!xdr_bool(xdrsp, &false))
44838460Smckusick 		return (0);
44938460Smckusick 	return (1);
45038460Smckusick errout:
45138460Smckusick 	sigsetmask(omask);
45238460Smckusick 	return (0);
45338460Smckusick }
45438460Smckusick 
45551898Smckusick /*
45651898Smckusick  * Called from xdr_explist() to traverse the tree and export the
45751898Smckusick  * directory paths.
45851898Smckusick  */
459*64903Smckusick put_exlist(dp, xdrsp, adp, putdefp)
46051898Smckusick 	register struct dirlist *dp;
46151898Smckusick 	XDR *xdrsp;
46251898Smckusick 	struct dirlist *adp;
463*64903Smckusick 	int *putdefp;
46451898Smckusick {
46551898Smckusick 	register struct grouplist *grp;
46651898Smckusick 	register struct hostlist *hp;
46751898Smckusick 	struct in_addr inaddr;
46851898Smckusick 	int true = 1;
46951898Smckusick 	int false = 0;
47051898Smckusick 	int gotalldir = 0;
47151898Smckusick 	char *strp;
47251898Smckusick 
47351898Smckusick 	if (dp) {
474*64903Smckusick 		if (put_exlist(dp->dp_left, xdrsp, adp, putdefp))
47551898Smckusick 			return (1);
47651898Smckusick 		if (!xdr_bool(xdrsp, &true))
47751898Smckusick 			return (1);
47851898Smckusick 		strp = dp->dp_dirp;
47951898Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
48051898Smckusick 			return (1);
481*64903Smckusick 		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
48251898Smckusick 			gotalldir = 1;
483*64903Smckusick 			*putdefp = 1;
484*64903Smckusick 		}
48551898Smckusick 		if ((dp->dp_flag & DP_DEFSET) == 0 &&
48651898Smckusick 		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
48751898Smckusick 			hp = dp->dp_hosts;
48851898Smckusick 			while (hp) {
48951898Smckusick 				grp = hp->ht_grp;
49051898Smckusick 				if (grp->gr_type == GT_HOST) {
49151898Smckusick 					if (!xdr_bool(xdrsp, &true))
49251898Smckusick 						return (1);
49351898Smckusick 					strp = grp->gr_ptr.gt_hostent->h_name;
49451898Smckusick 					if (!xdr_string(xdrsp, &strp,
49551898Smckusick 					    RPCMNT_NAMELEN))
49651898Smckusick 						return (1);
49751898Smckusick 				} else if (grp->gr_type == GT_NET) {
49851898Smckusick 					if (!xdr_bool(xdrsp, &true))
49951898Smckusick 						return (1);
50051898Smckusick 					strp = grp->gr_ptr.gt_net.nt_name;
50151898Smckusick 					if (!xdr_string(xdrsp, &strp,
50251898Smckusick 					    RPCMNT_NAMELEN))
50351898Smckusick 						return (1);
50451898Smckusick 				}
50551898Smckusick 				hp = hp->ht_next;
50651898Smckusick 				if (gotalldir && hp == (struct hostlist *)0) {
50751898Smckusick 					hp = adp->dp_hosts;
50851898Smckusick 					gotalldir = 0;
50951898Smckusick 				}
51051898Smckusick 			}
51151898Smckusick 		}
51251898Smckusick 		if (!xdr_bool(xdrsp, &false))
51351898Smckusick 			return (1);
514*64903Smckusick 		if (put_exlist(dp->dp_right, xdrsp, adp, putdefp))
51551898Smckusick 			return (1);
51651898Smckusick 	}
51751898Smckusick 	return (0);
51851898Smckusick }
51951898Smckusick 
52038460Smckusick #define LINESIZ	10240
52138460Smckusick char line[LINESIZ];
52251898Smckusick FILE *exp_file;
52338460Smckusick 
52438460Smckusick /*
52538460Smckusick  * Get the export list
52638460Smckusick  */
52746709Sbostic void
52838460Smckusick get_exportlist()
52938460Smckusick {
53038460Smckusick 	register struct exportlist *ep, *ep2;
53151898Smckusick 	register struct grouplist *grp, *tgrp;
53251898Smckusick 	struct exportlist **epp;
53351898Smckusick 	struct dirlist *dirhead;
53451898Smckusick 	struct stat sb;
53552109Smckusick 	struct statfs fsb, *fsp;
53651898Smckusick 	struct hostent *hpe;
53751898Smckusick 	struct ucred anon;
53852109Smckusick 	struct ufs_args targs;
53953150Smckusick 	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
54053150Smckusick 	int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
54138460Smckusick 
54238460Smckusick 	/*
54338460Smckusick 	 * First, get rid of the old list
54438460Smckusick 	 */
54551898Smckusick 	ep = exphead;
54651898Smckusick 	while (ep) {
54738460Smckusick 		ep2 = ep;
54838460Smckusick 		ep = ep->ex_next;
54944015Smckusick 		free_exp(ep2);
55038460Smckusick 	}
55151898Smckusick 	exphead = (struct exportlist *)0;
55238460Smckusick 
55351898Smckusick 	grp = grphead;
55451898Smckusick 	while (grp) {
55551898Smckusick 		tgrp = grp;
55651898Smckusick 		grp = grp->gr_next;
55751898Smckusick 		free_grp(tgrp);
55851667Smckusick 	}
55951898Smckusick 	grphead = (struct grouplist *)0;
56051667Smckusick 
56138460Smckusick 	/*
56252109Smckusick 	 * And delete exports that are in the kernel for all local
56352109Smckusick 	 * file systems.
56452109Smckusick 	 * XXX: Should know how to handle all local exportable file systems
56552109Smckusick 	 *      instead of just MOUNT_UFS.
56652109Smckusick 	 */
56753214Smckusick 	num = getmntinfo(&fsp, MNT_NOWAIT);
56852109Smckusick 	for (i = 0; i < num; i++) {
56952109Smckusick 		if (fsp->f_type == MOUNT_UFS) {
57052109Smckusick 			targs.fspec = (char *)0;
57152109Smckusick 			targs.exflags = MNT_DELEXPORT;
57252109Smckusick 			if (mount(fsp->f_type, fsp->f_mntonname,
57352109Smckusick 			    fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0)
57452109Smckusick 				syslog(LOG_ERR, "Can't del exports %s",
57552109Smckusick 				       fsp->f_mntonname);
57652109Smckusick 		}
57752109Smckusick 		fsp++;
57852109Smckusick 	}
57952109Smckusick 
58052109Smckusick 	/*
58138460Smckusick 	 * Read in the exports file and build the list, calling
58251667Smckusick 	 * mount() as we go along to push the export rules into the kernel.
58338460Smckusick 	 */
58451898Smckusick 	if ((exp_file = fopen(exname, "r")) == NULL) {
58538460Smckusick 		syslog(LOG_ERR, "Can't open %s", exname);
58638460Smckusick 		exit(2);
58738460Smckusick 	}
58851898Smckusick 	dirhead = (struct dirlist *)0;
58951898Smckusick 	while (get_line()) {
59051667Smckusick 		if (debug)
59151667Smckusick 			fprintf(stderr,"Got line %s\n",line);
59238460Smckusick 		cp = line;
59338460Smckusick 		nextfield(&cp, &endcp);
59451667Smckusick 		if (*cp == '#')
59551667Smckusick 			goto nextline;
59651898Smckusick 
59751898Smckusick 		/*
59851898Smckusick 		 * Set defaults.
59951898Smckusick 		 */
60051898Smckusick 		has_host = FALSE;
60151898Smckusick 		anon = def_anon;
60251667Smckusick 		exflags = MNT_EXPORTED;
60351898Smckusick 		got_nondir = 0;
60451898Smckusick 		opt_flags = 0;
60551898Smckusick 		ep = (struct exportlist *)0;
60644015Smckusick 
60744015Smckusick 		/*
60844015Smckusick 		 * Create new exports list entry
60944015Smckusick 		 */
61038460Smckusick 		len = endcp-cp;
61153150Smckusick 		tgrp = grp = get_grp();
61251898Smckusick 		while (len > 0) {
61351898Smckusick 			if (len > RPCMNT_NAMELEN) {
61453150Smckusick 			    getexp_err(ep, tgrp);
61551898Smckusick 			    goto nextline;
61651667Smckusick 			}
61745271Smckusick 			if (*cp == '-') {
61851898Smckusick 			    if (ep == (struct exportlist *)0) {
61953150Smckusick 				getexp_err(ep, tgrp);
62051898Smckusick 				goto nextline;
62151898Smckusick 			    }
62251898Smckusick 			    if (debug)
62351898Smckusick 				fprintf(stderr, "doing opt %s\n", cp);
62451898Smckusick 			    got_nondir = 1;
62551898Smckusick 			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
62651898Smckusick 				&exflags, &anon)) {
62753150Smckusick 				getexp_err(ep, tgrp);
62851898Smckusick 				goto nextline;
62951898Smckusick 			    }
63051898Smckusick 			} else if (*cp == '/') {
63151898Smckusick 			    savedc = *endcp;
63251898Smckusick 			    *endcp = '\0';
63351898Smckusick 			    if (stat(cp, &sb) >= 0 &&
63451898Smckusick 				(sb.st_mode & S_IFMT) == S_IFDIR &&
63551898Smckusick 				statfs(cp, &fsb) >= 0) {
63651898Smckusick 				if (got_nondir) {
63751898Smckusick 				    syslog(LOG_ERR, "Dirs must be first");
63853150Smckusick 				    getexp_err(ep, tgrp);
63951898Smckusick 				    goto nextline;
64051898Smckusick 				}
64151898Smckusick 				if (ep) {
64251898Smckusick 				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
64351898Smckusick 					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
64453150Smckusick 					getexp_err(ep, tgrp);
64551898Smckusick 					goto nextline;
64651898Smckusick 				    }
64751667Smckusick 				} else {
64851898Smckusick 				    /*
64951898Smckusick 				     * See if this directory is already
65051898Smckusick 				     * in the list.
65151898Smckusick 				     */
65251898Smckusick 				    ep = ex_search(&fsb.f_fsid);
65351898Smckusick 				    if (ep == (struct exportlist *)0) {
65451898Smckusick 					ep = get_exp();
65551898Smckusick 					ep->ex_fs = fsb.f_fsid;
65651898Smckusick 					ep->ex_fsdir = (char *)
65751898Smckusick 					    malloc(strlen(fsb.f_mntonname) + 1);
65851898Smckusick 					if (ep->ex_fsdir)
65951898Smckusick 					    strcpy(ep->ex_fsdir,
66051898Smckusick 						fsb.f_mntonname);
66151898Smckusick 					else
66251898Smckusick 					    out_of_mem();
66351898Smckusick 					if (debug)
66451898Smckusick 					  fprintf(stderr,
66551898Smckusick 					      "Making new ep fs=0x%x,0x%x\n",
66651898Smckusick 					      fsb.f_fsid.val[0],
66751898Smckusick 					      fsb.f_fsid.val[1]);
66851898Smckusick 				    } else if (debug)
66951898Smckusick 					fprintf(stderr,
67051898Smckusick 					    "Found ep fs=0x%x,0x%x\n",
67151898Smckusick 					    fsb.f_fsid.val[0],
67251898Smckusick 					    fsb.f_fsid.val[1]);
67338460Smckusick 				}
67451898Smckusick 
67551898Smckusick 				/*
67651898Smckusick 				 * Add dirpath to export mount point.
67751898Smckusick 				 */
67851898Smckusick 				dirp = add_expdir(&dirhead, cp, len);
67951898Smckusick 				dirplen = len;
68051898Smckusick 			    } else {
68153150Smckusick 				getexp_err(ep, tgrp);
68251898Smckusick 				goto nextline;
68351898Smckusick 			    }
68451898Smckusick 			    *endcp = savedc;
68551898Smckusick 			} else {
68651898Smckusick 			    savedc = *endcp;
68751898Smckusick 			    *endcp = '\0';
68851898Smckusick 			    got_nondir = 1;
68953150Smckusick 			    if (ep == (struct exportlist *)0) {
69053150Smckusick 				getexp_err(ep, tgrp);
69151898Smckusick 				goto nextline;
69251898Smckusick 			    }
69353150Smckusick 
69453150Smckusick 			    /*
69553150Smckusick 			     * Get the host or netgroup.
69653150Smckusick 			     */
69753150Smckusick 			    setnetgrent(cp);
69853150Smckusick 			    netgrp = getnetgrent(&hst, &usr, &dom);
69953150Smckusick 			    do {
70053150Smckusick 				if (has_host) {
70153150Smckusick 				    grp->gr_next = get_grp();
70253150Smckusick 				    grp = grp->gr_next;
70353150Smckusick 				}
70453150Smckusick 				if (netgrp) {
70553150Smckusick 				    if (get_host(hst, grp)) {
70653150Smckusick 					syslog(LOG_ERR, "Bad netgroup %s", cp);
70753150Smckusick 					getexp_err(ep, tgrp);
70853150Smckusick 					goto nextline;
70953150Smckusick 				    }
71053150Smckusick 				} else if (get_host(cp, grp)) {
71153150Smckusick 				    getexp_err(ep, tgrp);
71253150Smckusick 				    goto nextline;
71353150Smckusick 				}
71453150Smckusick 				has_host = TRUE;
71553150Smckusick 			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
71653150Smckusick 			    endnetgrent();
71751898Smckusick 			    *endcp = savedc;
71838460Smckusick 			}
71938460Smckusick 			cp = endcp;
72038460Smckusick 			nextfield(&cp, &endcp);
72145271Smckusick 			len = endcp - cp;
72238460Smckusick 		}
72351898Smckusick 		if (check_options(dirhead)) {
72453150Smckusick 			getexp_err(ep, tgrp);
72551898Smckusick 			goto nextline;
72651898Smckusick 		}
72751898Smckusick 		if (!has_host) {
72851898Smckusick 			grp->gr_type = GT_HOST;
72951667Smckusick 			if (debug)
73051667Smckusick 				fprintf(stderr,"Adding a default entry\n");
73151667Smckusick 			/* add a default group and make the grp list NULL */
73251667Smckusick 			hpe = (struct hostent *)malloc(sizeof(struct hostent));
73351898Smckusick 			if (hpe == (struct hostent *)0)
73451898Smckusick 				out_of_mem();
73551898Smckusick 			hpe->h_name = "Default";
73651667Smckusick 			hpe->h_addrtype = AF_INET;
73751667Smckusick 			hpe->h_length = sizeof (u_long);
73851712Smckusick 			hpe->h_addr_list = (char **)0;
73951898Smckusick 			grp->gr_ptr.gt_hostent = hpe;
74053150Smckusick 
74153150Smckusick 		/*
74253150Smckusick 		 * Don't allow a network export coincide with a list of
74353150Smckusick 		 * host(s) on the same line.
74453150Smckusick 		 */
74553150Smckusick 		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
74653150Smckusick 			getexp_err(ep, tgrp);
74753150Smckusick 			goto nextline;
74851667Smckusick 		}
74953150Smckusick 
75053150Smckusick 		/*
75153150Smckusick 		 * Loop through hosts, pushing the exports into the kernel.
75253150Smckusick 		 * After loop, tgrp points to the start of the list and
75353150Smckusick 		 * grp points to the last entry in the list.
75453150Smckusick 		 */
75553150Smckusick 		grp = tgrp;
75653150Smckusick 		do {
75753150Smckusick 		    if (do_mount(ep, grp, exflags, &anon, dirp,
75851898Smckusick 			dirplen, &fsb)) {
75953150Smckusick 			getexp_err(ep, tgrp);
76051898Smckusick 			goto nextline;
76153150Smckusick 		    }
76253150Smckusick 		} while (grp->gr_next && (grp = grp->gr_next));
76351898Smckusick 
76451898Smckusick 		/*
76551898Smckusick 		 * Success. Update the data structures.
76651898Smckusick 		 */
76751898Smckusick 		if (has_host) {
76853150Smckusick 			hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS));
76951898Smckusick 			grp->gr_next = grphead;
77053150Smckusick 			grphead = tgrp;
77151898Smckusick 		} else {
77251898Smckusick 			hang_dirp(dirhead, (struct grouplist *)0, ep,
77353150Smckusick 			(opt_flags & OP_ALLDIRS));
77451898Smckusick 			free_grp(grp);
77551898Smckusick 		}
77651898Smckusick 		dirhead = (struct dirlist *)0;
77751898Smckusick 		if ((ep->ex_flag & EX_LINKED) == 0) {
77851898Smckusick 			ep2 = exphead;
77951898Smckusick 			epp = &exphead;
78051898Smckusick 
78151898Smckusick 			/*
78251898Smckusick 			 * Insert in the list in alphabetical order.
78351898Smckusick 			 */
78451898Smckusick 			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
78551898Smckusick 				epp = &ep2->ex_next;
78651898Smckusick 				ep2 = ep2->ex_next;
78751898Smckusick 			}
78851898Smckusick 			if (ep2)
78951898Smckusick 				ep->ex_next = ep2;
79051898Smckusick 			*epp = ep;
79151898Smckusick 			ep->ex_flag |= EX_LINKED;
79251898Smckusick 		}
79351898Smckusick nextline:
79451898Smckusick 		if (dirhead) {
79551898Smckusick 			free_dir(dirhead);
79651898Smckusick 			dirhead = (struct dirlist *)0;
79751898Smckusick 		}
79851898Smckusick 	}
79951898Smckusick 	fclose(exp_file);
80051898Smckusick }
80151898Smckusick 
80251898Smckusick /*
80351898Smckusick  * Allocate an export list element
80451898Smckusick  */
80551898Smckusick struct exportlist *
80651898Smckusick get_exp()
80751898Smckusick {
80851898Smckusick 	register struct exportlist *ep;
80951898Smckusick 
81051898Smckusick 	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
81151898Smckusick 	if (ep == (struct exportlist *)0)
81251898Smckusick 		out_of_mem();
81351898Smckusick 	bzero((caddr_t)ep, sizeof (struct exportlist));
81451898Smckusick 	return (ep);
81551898Smckusick }
81651898Smckusick 
81751898Smckusick /*
81851898Smckusick  * Allocate a group list element
81951898Smckusick  */
82051898Smckusick struct grouplist *
82151898Smckusick get_grp()
82251898Smckusick {
82351898Smckusick 	register struct grouplist *gp;
82451898Smckusick 
82551898Smckusick 	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
82651898Smckusick 	if (gp == (struct grouplist *)0)
82751898Smckusick 		out_of_mem();
82851898Smckusick 	bzero((caddr_t)gp, sizeof (struct grouplist));
82951898Smckusick 	return (gp);
83051898Smckusick }
83151898Smckusick 
83251898Smckusick /*
83351898Smckusick  * Clean up upon an error in get_exportlist().
83451898Smckusick  */
83551898Smckusick void
83651898Smckusick getexp_err(ep, grp)
83751898Smckusick 	struct exportlist *ep;
83851898Smckusick 	struct grouplist *grp;
83951898Smckusick {
84053150Smckusick 	struct grouplist *tgrp;
84151898Smckusick 
84251898Smckusick 	syslog(LOG_ERR, "Bad exports list line %s", line);
84359017Smckusick 	if (ep && (ep->ex_flag & EX_LINKED) == 0)
84451898Smckusick 		free_exp(ep);
84553150Smckusick 	while (grp) {
84653150Smckusick 		tgrp = grp;
84753150Smckusick 		grp = grp->gr_next;
84853150Smckusick 		free_grp(tgrp);
84953150Smckusick 	}
85051898Smckusick }
85151898Smckusick 
85251898Smckusick /*
85351898Smckusick  * Search the export list for a matching fs.
85451898Smckusick  */
85551898Smckusick struct exportlist *
85651898Smckusick ex_search(fsid)
85752109Smckusick 	fsid_t *fsid;
85851898Smckusick {
85951898Smckusick 	register struct exportlist *ep;
86051898Smckusick 
86151898Smckusick 	ep = exphead;
86251898Smckusick 	while (ep) {
86351898Smckusick 		if (ep->ex_fs.val[0] == fsid->val[0] &&
86451898Smckusick 		    ep->ex_fs.val[1] == fsid->val[1])
86551898Smckusick 			return (ep);
86651898Smckusick 		ep = ep->ex_next;
86751898Smckusick 	}
86851898Smckusick 	return (ep);
86951898Smckusick }
87051898Smckusick 
87151898Smckusick /*
87251898Smckusick  * Add a directory path to the list.
87351898Smckusick  */
87451898Smckusick char *
87551898Smckusick add_expdir(dpp, cp, len)
87651898Smckusick 	struct dirlist **dpp;
87751898Smckusick 	char *cp;
87851898Smckusick 	int len;
87951898Smckusick {
88051898Smckusick 	register struct dirlist *dp;
88151898Smckusick 
88251898Smckusick 	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
88351898Smckusick 	dp->dp_left = *dpp;
88451898Smckusick 	dp->dp_right = (struct dirlist *)0;
88551898Smckusick 	dp->dp_flag = 0;
88651898Smckusick 	dp->dp_hosts = (struct hostlist *)0;
88751898Smckusick 	strcpy(dp->dp_dirp, cp);
88851898Smckusick 	*dpp = dp;
88951898Smckusick 	return (dp->dp_dirp);
89051898Smckusick }
89151898Smckusick 
89251898Smckusick /*
89351898Smckusick  * Hang the dir list element off the dirpath binary tree as required
89451898Smckusick  * and update the entry for host.
89551898Smckusick  */
89651898Smckusick void
89751898Smckusick hang_dirp(dp, grp, ep, alldirs)
89851898Smckusick 	register struct dirlist *dp;
89951898Smckusick 	struct grouplist *grp;
90051898Smckusick 	struct exportlist *ep;
90151898Smckusick 	int alldirs;
90251898Smckusick {
90351898Smckusick 	register struct hostlist *hp;
90451898Smckusick 	struct dirlist *dp2;
90551898Smckusick 
90651898Smckusick 	if (alldirs) {
90751898Smckusick 		if (ep->ex_defdir)
90851898Smckusick 			free((caddr_t)dp);
90951898Smckusick 		else
91051898Smckusick 			ep->ex_defdir = dp;
91155292Smckusick 		if (grp == (struct grouplist *)0)
91255292Smckusick 			ep->ex_defdir->dp_flag |= DP_DEFSET;
91355292Smckusick 		else while (grp) {
91451898Smckusick 			hp = get_ht();
91551898Smckusick 			hp->ht_grp = grp;
91651898Smckusick 			hp->ht_next = ep->ex_defdir->dp_hosts;
91751898Smckusick 			ep->ex_defdir->dp_hosts = hp;
91855292Smckusick 			grp = grp->gr_next;
91955292Smckusick 		}
92051898Smckusick 	} else {
92153150Smckusick 
92253150Smckusick 		/*
92353150Smckusick 		 * Loop throught the directories adding them to the tree.
92453150Smckusick 		 */
92551898Smckusick 		while (dp) {
92651898Smckusick 			dp2 = dp->dp_left;
92753150Smckusick 			add_dlist(&ep->ex_dirl, dp, grp);
92851898Smckusick 			dp = dp2;
92951898Smckusick 		}
93051898Smckusick 	}
93151898Smckusick }
93251898Smckusick 
93351898Smckusick /*
93451898Smckusick  * Traverse the binary tree either updating a node that is already there
93551898Smckusick  * for the new directory or adding the new node.
93651898Smckusick  */
93751898Smckusick void
93853150Smckusick add_dlist(dpp, newdp, grp)
93951898Smckusick 	struct dirlist **dpp;
94051898Smckusick 	struct dirlist *newdp;
94153150Smckusick 	register struct grouplist *grp;
94251898Smckusick {
94351898Smckusick 	register struct dirlist *dp;
94453150Smckusick 	register struct hostlist *hp;
94551898Smckusick 	int cmp;
94651898Smckusick 
94751898Smckusick 	dp = *dpp;
94851898Smckusick 	if (dp) {
94951898Smckusick 		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
95051898Smckusick 		if (cmp > 0) {
95153150Smckusick 			add_dlist(&dp->dp_left, newdp, grp);
95251898Smckusick 			return;
95351898Smckusick 		} else if (cmp < 0) {
95453150Smckusick 			add_dlist(&dp->dp_right, newdp, grp);
95551898Smckusick 			return;
95651898Smckusick 		} else
95751898Smckusick 			free((caddr_t)newdp);
95851898Smckusick 	} else {
95951898Smckusick 		dp = newdp;
96051898Smckusick 		dp->dp_left = (struct dirlist *)0;
96151898Smckusick 		*dpp = dp;
96251898Smckusick 	}
96353150Smckusick 	if (grp) {
96453150Smckusick 
96553150Smckusick 		/*
96653150Smckusick 		 * Hang all of the host(s) off of the directory point.
96753150Smckusick 		 */
96853150Smckusick 		do {
96953150Smckusick 			hp = get_ht();
97053150Smckusick 			hp->ht_grp = grp;
97153150Smckusick 			hp->ht_next = dp->dp_hosts;
97253150Smckusick 			dp->dp_hosts = hp;
97353150Smckusick 			grp = grp->gr_next;
97453150Smckusick 		} while (grp);
97551898Smckusick 	} else
97651898Smckusick 		dp->dp_flag |= DP_DEFSET;
97751898Smckusick }
97851898Smckusick 
97951898Smckusick /*
98051898Smckusick  * Search for a dirpath on the export point.
98151898Smckusick  */
98251898Smckusick struct dirlist *
98351898Smckusick dirp_search(dp, dirpath)
98451898Smckusick 	register struct dirlist *dp;
98551898Smckusick 	char *dirpath;
98651898Smckusick {
98751898Smckusick 	register int cmp;
98851898Smckusick 
98951898Smckusick 	if (dp) {
99051898Smckusick 		cmp = strcmp(dp->dp_dirp, dirpath);
99151898Smckusick 		if (cmp > 0)
99251898Smckusick 			return (dirp_search(dp->dp_left, dirpath));
99351898Smckusick 		else if (cmp < 0)
99451898Smckusick 			return (dirp_search(dp->dp_right, dirpath));
99551898Smckusick 		else
99651898Smckusick 			return (dp);
99751898Smckusick 	}
99851898Smckusick 	return (dp);
99951898Smckusick }
100051898Smckusick 
100151898Smckusick /*
100251898Smckusick  * Scan for a host match in a directory tree.
100351898Smckusick  */
100451898Smckusick chk_host(dp, saddr, defsetp)
100551898Smckusick 	struct dirlist *dp;
100651898Smckusick 	u_long saddr;
100751898Smckusick 	int *defsetp;
100851898Smckusick {
100951898Smckusick 	register struct hostlist *hp;
101051898Smckusick 	register struct grouplist *grp;
101151898Smckusick 	register u_long **addrp;
101251898Smckusick 
101351898Smckusick 	if (dp) {
101451898Smckusick 		if (dp->dp_flag & DP_DEFSET)
101551898Smckusick 			*defsetp = 1;
101651898Smckusick 		hp = dp->dp_hosts;
101751898Smckusick 		while (hp) {
101851898Smckusick 			grp = hp->ht_grp;
101951898Smckusick 			switch (grp->gr_type) {
102051898Smckusick 			case GT_HOST:
102151898Smckusick 			    addrp = (u_long **)
102251898Smckusick 				grp->gr_ptr.gt_hostent->h_addr_list;
102351898Smckusick 			    while (*addrp) {
102451898Smckusick 				if (**addrp == saddr)
102551898Smckusick 				    return (1);
102651898Smckusick 				addrp++;
102751898Smckusick 			    }
102851898Smckusick 			    break;
102951898Smckusick 			case GT_NET:
103051898Smckusick 			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
103151898Smckusick 				grp->gr_ptr.gt_net.nt_net)
103251898Smckusick 				return (1);
103351898Smckusick 			    break;
103451898Smckusick 			};
103551898Smckusick 			hp = hp->ht_next;
103651898Smckusick 		}
103751898Smckusick 	}
103851898Smckusick 	return (0);
103951898Smckusick }
104051898Smckusick 
104151898Smckusick /*
104251898Smckusick  * Scan tree for a host that matches the address.
104351898Smckusick  */
104451898Smckusick scan_tree(dp, saddr)
104551898Smckusick 	register struct dirlist *dp;
104651898Smckusick 	u_long saddr;
104751898Smckusick {
104851898Smckusick 	int defset;
104951898Smckusick 
105051898Smckusick 	if (dp) {
105151898Smckusick 		if (scan_tree(dp->dp_left, saddr))
105251898Smckusick 			return (1);
105351898Smckusick 		if (chk_host(dp, saddr, &defset))
105451898Smckusick 			return (1);
105551898Smckusick 		if (scan_tree(dp->dp_right, saddr))
105651898Smckusick 			return (1);
105751898Smckusick 	}
105851898Smckusick 	return (0);
105951898Smckusick }
106051898Smckusick 
106151898Smckusick /*
106251898Smckusick  * Traverse the dirlist tree and free it up.
106351898Smckusick  */
106451898Smckusick void
106551898Smckusick free_dir(dp)
106651898Smckusick 	register struct dirlist *dp;
106751898Smckusick {
106851898Smckusick 
106951898Smckusick 	if (dp) {
107051898Smckusick 		free_dir(dp->dp_left);
107151898Smckusick 		free_dir(dp->dp_right);
107251898Smckusick 		free_host(dp->dp_hosts);
107351898Smckusick 		free((caddr_t)dp);
107451898Smckusick 	}
107551898Smckusick }
107651898Smckusick 
107751898Smckusick /*
107851898Smckusick  * Parse the option string and update fields.
107951898Smckusick  * Option arguments may either be -<option>=<value> or
108051898Smckusick  * -<option> <value>
108151898Smckusick  */
108251898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
108351898Smckusick 	char **cpp, **endcpp;
108451898Smckusick 	struct exportlist *ep;
108551898Smckusick 	struct grouplist *grp;
108651898Smckusick 	int *has_hostp;
108751898Smckusick 	int *exflagsp;
108851898Smckusick 	struct ucred *cr;
108951898Smckusick {
109051898Smckusick 	register char *cpoptarg, *cpoptend;
109151898Smckusick 	char *cp, *endcp, *cpopt, savedc, savedc2;
109251898Smckusick 	int allflag, usedarg;
109351898Smckusick 
109451898Smckusick 	cpopt = *cpp;
109551898Smckusick 	cpopt++;
109651898Smckusick 	cp = *endcpp;
109751898Smckusick 	savedc = *cp;
109851898Smckusick 	*cp = '\0';
109951898Smckusick 	while (cpopt && *cpopt) {
110051898Smckusick 		allflag = 1;
110151898Smckusick 		usedarg = -2;
110251898Smckusick 		if (cpoptend = index(cpopt, ',')) {
110351898Smckusick 			*cpoptend++ = '\0';
110451898Smckusick 			if (cpoptarg = index(cpopt, '='))
110551898Smckusick 				*cpoptarg++ = '\0';
110651898Smckusick 		} else {
110751898Smckusick 			if (cpoptarg = index(cpopt, '='))
110851898Smckusick 				*cpoptarg++ = '\0';
110951898Smckusick 			else {
111051898Smckusick 				*cp = savedc;
111151898Smckusick 				nextfield(&cp, &endcp);
111251898Smckusick 				**endcpp = '\0';
111351898Smckusick 				if (endcp > cp && *cp != '-') {
111451898Smckusick 					cpoptarg = cp;
111551898Smckusick 					savedc2 = *endcp;
111651898Smckusick 					*endcp = '\0';
111751898Smckusick 					usedarg = 0;
111851667Smckusick 				}
111951667Smckusick 			}
112051667Smckusick 		}
112151898Smckusick 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
112251898Smckusick 			*exflagsp |= MNT_EXRDONLY;
112351898Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
112451898Smckusick 		    !(allflag = strcmp(cpopt, "mapall")) ||
112551898Smckusick 		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
112651898Smckusick 			usedarg++;
112751898Smckusick 			parsecred(cpoptarg, cr);
112851898Smckusick 			if (allflag == 0) {
112951898Smckusick 				*exflagsp |= MNT_EXPORTANON;
113051898Smckusick 				opt_flags |= OP_MAPALL;
113151898Smckusick 			} else
113251898Smckusick 				opt_flags |= OP_MAPROOT;
113351898Smckusick 		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
113451898Smckusick 			*exflagsp |= MNT_EXKERB;
113551898Smckusick 			opt_flags |= OP_KERB;
113653150Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
113753150Smckusick 			!strcmp(cpopt, "m"))) {
113851898Smckusick 			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
113951898Smckusick 				syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
114051898Smckusick 				return (1);
114151898Smckusick 			}
114251898Smckusick 			usedarg++;
114351898Smckusick 			opt_flags |= OP_MASK;
114453150Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
114553150Smckusick 			!strcmp(cpopt, "n"))) {
114651898Smckusick 			if (grp->gr_type != GT_NULL) {
114751898Smckusick 				syslog(LOG_ERR, "Network/host conflict");
114851898Smckusick 				return (1);
114951898Smckusick 			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
115051898Smckusick 				syslog(LOG_ERR, "Bad net: %s", cpoptarg);
115151898Smckusick 				return (1);
115251898Smckusick 			}
115351898Smckusick 			grp->gr_type = GT_NET;
115451898Smckusick 			*has_hostp = 1;
115551898Smckusick 			usedarg++;
115651898Smckusick 			opt_flags |= OP_NET;
115751898Smckusick 		} else if (!strcmp(cpopt, "alldirs")) {
115851898Smckusick 			opt_flags |= OP_ALLDIRS;
115951898Smckusick #ifdef ISO
116051898Smckusick 		} else if (cpoptarg && !strcmp(cpopt, "iso")) {
116151898Smckusick 			if (get_isoaddr(cpoptarg, grp)) {
116251898Smckusick 				syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
116351898Smckusick 				return (1);
116451898Smckusick 			}
116551898Smckusick 			*has_hostp = 1;
116651898Smckusick 			usedarg++;
116751898Smckusick 			opt_flags |= OP_ISO;
116851898Smckusick #endif /* ISO */
116951898Smckusick 		} else {
117051898Smckusick 			syslog(LOG_ERR, "Bad opt %s", cpopt);
117151898Smckusick 			return (1);
117251667Smckusick 		}
117351898Smckusick 		if (usedarg >= 0) {
117451898Smckusick 			*endcp = savedc2;
117551898Smckusick 			**endcpp = savedc;
117651898Smckusick 			if (usedarg > 0) {
117751898Smckusick 				*cpp = cp;
117851898Smckusick 				*endcpp = endcp;
117951898Smckusick 			}
118051898Smckusick 			return (0);
118151898Smckusick 		}
118251898Smckusick 		cpopt = cpoptend;
118351667Smckusick 	}
118451898Smckusick 	**endcpp = savedc;
118551898Smckusick 	return (0);
118651898Smckusick }
118751898Smckusick 
118851898Smckusick /*
118951898Smckusick  * Translate a character string to the corresponding list of network
119051898Smckusick  * addresses for a hostname.
119151898Smckusick  */
119251898Smckusick get_host(cp, grp)
119351898Smckusick 	char *cp;
119451898Smckusick 	register struct grouplist *grp;
119551898Smckusick {
119651898Smckusick 	register struct hostent *hp, *nhp;
119751898Smckusick 	register char **addrp, **naddrp;
119851898Smckusick 	struct hostent t_host;
119951898Smckusick 	int i;
120051898Smckusick 	u_long saddr;
120151898Smckusick 	char *aptr[2];
120251898Smckusick 
120351898Smckusick 	if (grp->gr_type != GT_NULL)
120451898Smckusick 		return (1);
120551898Smckusick 	if ((hp = gethostbyname(cp)) == NULL) {
120651898Smckusick 		if (isdigit(*cp)) {
120751898Smckusick 			saddr = inet_addr(cp);
120851898Smckusick 			if (saddr == -1) {
120951898Smckusick 				syslog(LOG_ERR, "Inet_addr failed");
121051898Smckusick 				return (1);
121151898Smckusick 			}
121251898Smckusick 			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
121351898Smckusick 				AF_INET)) == NULL) {
121451898Smckusick 				hp = &t_host;
121551898Smckusick 				hp->h_name = cp;
121651898Smckusick 				hp->h_addrtype = AF_INET;
121751898Smckusick 				hp->h_length = sizeof (u_long);
121851898Smckusick 				hp->h_addr_list = aptr;
121951898Smckusick 				aptr[0] = (char *)&saddr;
122051898Smckusick 				aptr[1] = (char *)0;
122151898Smckusick 			}
122251898Smckusick 		} else {
122351898Smckusick 			syslog(LOG_ERR, "Gethostbyname failed");
122451898Smckusick 			return (1);
122551898Smckusick 		}
122651898Smckusick 	}
122751898Smckusick 	grp->gr_type = GT_HOST;
122851898Smckusick 	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
122951898Smckusick 		malloc(sizeof(struct hostent));
123051898Smckusick 	if (nhp == (struct hostent *)0)
123151898Smckusick 		out_of_mem();
123251898Smckusick 	bcopy((caddr_t)hp, (caddr_t)nhp,
123351898Smckusick 		sizeof(struct hostent));
123451898Smckusick 	i = strlen(hp->h_name)+1;
123551898Smckusick 	nhp->h_name = (char *)malloc(i);
123651898Smckusick 	if (nhp->h_name == (char *)0)
123751898Smckusick 		out_of_mem();
123851898Smckusick 	bcopy(hp->h_name, nhp->h_name, i);
123951898Smckusick 	addrp = hp->h_addr_list;
124051898Smckusick 	i = 1;
124151898Smckusick 	while (*addrp++)
124251898Smckusick 		i++;
124351898Smckusick 	naddrp = nhp->h_addr_list = (char **)
124451898Smckusick 		malloc(i*sizeof(char *));
124551898Smckusick 	if (naddrp == (char **)0)
124651898Smckusick 		out_of_mem();
124751898Smckusick 	addrp = hp->h_addr_list;
124851898Smckusick 	while (*addrp) {
124951898Smckusick 		*naddrp = (char *)
125051898Smckusick 		    malloc(hp->h_length);
125151898Smckusick 		if (*naddrp == (char *)0)
125251898Smckusick 		    out_of_mem();
125351898Smckusick 		bcopy(*addrp, *naddrp,
125451898Smckusick 			hp->h_length);
125551898Smckusick 		addrp++;
125651898Smckusick 		naddrp++;
125751898Smckusick 	}
125851898Smckusick 	*naddrp = (char *)0;
125953150Smckusick 	if (debug)
126053150Smckusick 		fprintf(stderr, "got host %s\n", hp->h_name);
126151898Smckusick 	return (0);
126251898Smckusick }
126351898Smckusick 
126451898Smckusick /*
126551898Smckusick  * Free up an exports list component
126651898Smckusick  */
126751898Smckusick void
126851898Smckusick free_exp(ep)
126951898Smckusick 	register struct exportlist *ep;
127051898Smckusick {
127151898Smckusick 
127251898Smckusick 	if (ep->ex_defdir) {
127351898Smckusick 		free_host(ep->ex_defdir->dp_hosts);
127451898Smckusick 		free((caddr_t)ep->ex_defdir);
127551898Smckusick 	}
127651898Smckusick 	if (ep->ex_fsdir)
127751898Smckusick 		free(ep->ex_fsdir);
127851898Smckusick 	free_dir(ep->ex_dirl);
127951898Smckusick 	free((caddr_t)ep);
128051898Smckusick }
128151898Smckusick 
128251898Smckusick /*
128351898Smckusick  * Free hosts.
128451898Smckusick  */
128551898Smckusick void
128651898Smckusick free_host(hp)
128751898Smckusick 	register struct hostlist *hp;
128851898Smckusick {
128951898Smckusick 	register struct hostlist *hp2;
129051898Smckusick 
129151898Smckusick 	while (hp) {
129251898Smckusick 		hp2 = hp;
129351898Smckusick 		hp = hp->ht_next;
129451898Smckusick 		free((caddr_t)hp2);
129551898Smckusick 	}
129651898Smckusick }
129751898Smckusick 
129851898Smckusick struct hostlist *
129951898Smckusick get_ht()
130051898Smckusick {
130151898Smckusick 	register struct hostlist *hp;
130251898Smckusick 
130351898Smckusick 	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
130451898Smckusick 	if (hp == (struct hostlist *)0)
130551898Smckusick 		out_of_mem();
130651898Smckusick 	hp->ht_next = (struct hostlist *)0;
130751898Smckusick 	return (hp);
130851898Smckusick }
130951898Smckusick 
131051898Smckusick #ifdef ISO
131151898Smckusick /*
131251898Smckusick  * Translate an iso address.
131351898Smckusick  */
131451898Smckusick get_isoaddr(cp, grp)
131551898Smckusick 	char *cp;
131651898Smckusick 	struct grouplist *grp;
131751898Smckusick {
131851898Smckusick 	struct iso_addr *isop;
131951898Smckusick 	struct sockaddr_iso *isoaddr;
132051898Smckusick 
132151898Smckusick 	if (grp->gr_type != GT_NULL)
132251898Smckusick 		return (1);
132351898Smckusick 	if ((isop = iso_addr(cp)) == NULL) {
132451898Smckusick 		syslog(LOG_ERR,
132551898Smckusick 		    "iso_addr failed, ignored");
132651898Smckusick 		return (1);
132751898Smckusick 	}
132851898Smckusick 	isoaddr = (struct sockaddr_iso *)
132951898Smckusick 	    malloc(sizeof (struct sockaddr_iso));
133051898Smckusick 	if (isoaddr == (struct sockaddr_iso *)0)
133151898Smckusick 		out_of_mem();
133251898Smckusick 	bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
133351898Smckusick 	bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr,
133451898Smckusick 		sizeof (struct iso_addr));
133551898Smckusick 	isoaddr->siso_len = sizeof (struct sockaddr_iso);
133651898Smckusick 	isoaddr->siso_family = AF_ISO;
133751898Smckusick 	grp->gr_type = GT_ISO;
133851898Smckusick 	grp->gr_ptr.gt_isoaddr = isoaddr;
133951898Smckusick 	return (0);
134051898Smckusick }
134151898Smckusick #endif	/* ISO */
134251898Smckusick 
134351898Smckusick /*
134451898Smckusick  * Out of memory, fatal
134551898Smckusick  */
134651898Smckusick void
134751898Smckusick out_of_mem()
134851898Smckusick {
134951898Smckusick 
135051898Smckusick 	syslog(LOG_ERR, "Out of memory");
135151667Smckusick 	exit(2);
135251667Smckusick }
135351667Smckusick 
135451898Smckusick /*
135551898Smckusick  * Do the mount syscall with the update flag to push the export info into
135651898Smckusick  * the kernel.
135751898Smckusick  */
135851898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
135951667Smckusick 	struct exportlist *ep;
136051667Smckusick 	struct grouplist *grp;
136151898Smckusick 	int exflags;
136251667Smckusick 	struct ucred *anoncrp;
136351898Smckusick 	char *dirp;
136451898Smckusick 	int dirplen;
136551898Smckusick 	struct statfs *fsb;
136651667Smckusick {
136751898Smckusick 	register char *cp = (char *)0;
136851667Smckusick 	register u_long **addrp;
136951898Smckusick 	int done;
137051898Smckusick 	char savedc;
137151898Smckusick 	struct sockaddr_in sin, imask;
137252109Smckusick 	struct ufs_args args;
137351898Smckusick 	u_long net;
137451667Smckusick 
137551667Smckusick 	args.fspec = 0;
137651667Smckusick 	args.exflags = exflags;
137751667Smckusick 	args.anon = *anoncrp;
137855878Smckusick 	bzero((char *)&sin, sizeof(sin));
137955878Smckusick 	bzero((char *)&imask, sizeof(imask));
138051667Smckusick 	sin.sin_family = AF_INET;
138151667Smckusick 	sin.sin_len = sizeof(sin);
138251898Smckusick 	imask.sin_family = AF_INET;
138351898Smckusick 	imask.sin_len = sizeof(sin);
138451898Smckusick 	if (grp->gr_type == GT_HOST)
138551667Smckusick 		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
138651898Smckusick 	else
138751898Smckusick 		addrp = (u_long **)0;
138851667Smckusick 	done = FALSE;
138951898Smckusick 	while (!done) {
139051898Smckusick 		switch (grp->gr_type) {
139151898Smckusick 		case GT_HOST:
1392*64903Smckusick 			if (addrp) {
139351712Smckusick 				sin.sin_addr.s_addr = **addrp;
1394*64903Smckusick 				args.slen = sizeof(sin);
1395*64903Smckusick 			} else
1396*64903Smckusick 				args.slen = 0;
139751667Smckusick 			args.saddr = (struct sockaddr *)&sin;
139851898Smckusick 			args.msklen = 0;
139951898Smckusick 			break;
140051898Smckusick 		case GT_NET:
140151898Smckusick 			if (grp->gr_ptr.gt_net.nt_mask)
140251898Smckusick 			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
140351898Smckusick 			else {
140451898Smckusick 			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
140551898Smckusick 			    if (IN_CLASSA(net))
140651898Smckusick 				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
140751898Smckusick 			    else if (IN_CLASSB(net))
140851898Smckusick 				imask.sin_addr.s_addr =
140951898Smckusick 				    inet_addr("255.255.0.0");
141051898Smckusick 			    else
141151898Smckusick 				imask.sin_addr.s_addr =
141251898Smckusick 				    inet_addr("255.255.255.0");
141351898Smckusick 			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
141451898Smckusick 			}
141551898Smckusick 			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
141651898Smckusick 			args.saddr = (struct sockaddr *)&sin;
141751898Smckusick 			args.slen = sizeof (sin);
141851898Smckusick 			args.smask = (struct sockaddr *)&imask;
141951898Smckusick 			args.msklen = sizeof (imask);
142051898Smckusick 			break;
142151667Smckusick #ifdef ISO
142251898Smckusick 		case GT_ISO:
142351667Smckusick 			args.saddr = (struct sockaddr *)grp->gr_ptr.gt_isoaddr;
142451667Smckusick 			args.slen = sizeof (struct sockaddr_iso);
142551898Smckusick 			args.msklen = 0;
142651898Smckusick 			break;
142751667Smckusick #endif	/* ISO */
142851898Smckusick 		default:
142951667Smckusick 			syslog(LOG_ERR, "Bad grouptype");
143051898Smckusick 			if (cp)
143151898Smckusick 				*cp = savedc;
143251898Smckusick 			return (1);
143351898Smckusick 		};
143452109Smckusick 
143552109Smckusick 		/*
143652109Smckusick 		 * XXX:
143752109Smckusick 		 * Maybe I should just use the fsb->f_mntonname path instead
143852109Smckusick 		 * of looping back up the dirp to the mount point??
143952109Smckusick 		 * Also, needs to know how to export all types of local
144052109Smckusick 		 * exportable file systems and not just MOUNT_UFS.
144152109Smckusick 		 */
144252109Smckusick 		while (mount(fsb->f_type, dirp,
144352109Smckusick 		       fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
144451898Smckusick 			if (cp)
144551898Smckusick 				*cp-- = savedc;
144651898Smckusick 			else
144751898Smckusick 				cp = dirp + dirplen - 1;
144851667Smckusick 			if (errno == EPERM) {
144951667Smckusick 				syslog(LOG_ERR,
145051898Smckusick 				   "Can't change attributes for %s.\n", dirp);
145151898Smckusick 				return (1);
145251667Smckusick 			}
145351898Smckusick 			if (opt_flags & OP_ALLDIRS) {
145451898Smckusick 				syslog(LOG_ERR, "Not root dir");
145551898Smckusick 				return (1);
145651898Smckusick 			}
145751667Smckusick 			/* back up over the last component */
145851898Smckusick 			while (*cp == '/' && cp > dirp)
145951667Smckusick 				cp--;
146051898Smckusick 			while (*(cp - 1) != '/' && cp > dirp)
146151667Smckusick 				cp--;
146251898Smckusick 			if (cp == dirp) {
146351898Smckusick 				if (debug)
146451667Smckusick 					fprintf(stderr,"mnt unsucc\n");
146551898Smckusick 				syslog(LOG_ERR, "Can't export %s", dirp);
146651898Smckusick 				return (1);
146751667Smckusick 			}
146851667Smckusick 			savedc = *cp;
146951667Smckusick 			*cp = '\0';
147051667Smckusick 		}
147151898Smckusick 		if (addrp) {
147251667Smckusick 			++addrp;
147351898Smckusick 			if (*addrp == (u_long *)0)
147451667Smckusick 				done = TRUE;
147551898Smckusick 		} else
147651898Smckusick 			done = TRUE;
147751898Smckusick 	}
147851898Smckusick 	if (cp)
147951898Smckusick 		*cp = savedc;
148051898Smckusick 	return (0);
148151898Smckusick }
148251898Smckusick 
148351898Smckusick /*
148451898Smckusick  * Translate a net address.
148551898Smckusick  */
148651898Smckusick get_net(cp, net, maskflg)
148751898Smckusick 	char *cp;
148851898Smckusick 	struct netmsk *net;
148951898Smckusick 	int maskflg;
149051898Smckusick {
149151898Smckusick 	register struct netent *np;
149251898Smckusick 	register long netaddr;
149351898Smckusick 	struct in_addr inetaddr, inetaddr2;
149451898Smckusick 	char *name;
149551898Smckusick 
149651898Smckusick 	if (np = getnetbyname(cp))
149751898Smckusick 		inetaddr = inet_makeaddr(np->n_net, 0);
149851898Smckusick 	else if (isdigit(*cp)) {
149951898Smckusick 		if ((netaddr = inet_network(cp)) == -1)
150051898Smckusick 			return (1);
150151898Smckusick 		inetaddr = inet_makeaddr(netaddr, 0);
150251898Smckusick 		/*
150351898Smckusick 		 * Due to arbritrary subnet masks, you don't know how many
150451898Smckusick 		 * bits to shift the address to make it into a network,
150551898Smckusick 		 * however you do know how to make a network address into
150651898Smckusick 		 * a host with host == 0 and then compare them.
150751898Smckusick 		 * (What a pest)
150851898Smckusick 		 */
150951898Smckusick 		if (!maskflg) {
151051898Smckusick 			setnetent(0);
151151898Smckusick 			while (np = getnetent()) {
151251898Smckusick 				inetaddr2 = inet_makeaddr(np->n_net, 0);
151351898Smckusick 				if (inetaddr2.s_addr == inetaddr.s_addr)
151451898Smckusick 					break;
151551898Smckusick 			}
151651898Smckusick 			endnetent();
151751667Smckusick 		}
151851898Smckusick 	} else
151951898Smckusick 		return (1);
152051898Smckusick 	if (maskflg)
152151898Smckusick 		net->nt_mask = inetaddr.s_addr;
152251898Smckusick 	else {
152351898Smckusick 		if (np)
152451898Smckusick 			name = np->n_name;
152551898Smckusick 		else
152651898Smckusick 			name = inet_ntoa(inetaddr);
152751898Smckusick 		net->nt_name = (char *)malloc(strlen(name) + 1);
152851898Smckusick 		if (net->nt_name == (char *)0)
152951898Smckusick 			out_of_mem();
153051898Smckusick 		strcpy(net->nt_name, name);
153151898Smckusick 		net->nt_net = inetaddr.s_addr;
153238460Smckusick 	}
153351898Smckusick 	return (0);
153438460Smckusick }
153538460Smckusick 
153638460Smckusick /*
153738460Smckusick  * Parse out the next white space separated field
153838460Smckusick  */
153951667Smckusick void
154038460Smckusick nextfield(cp, endcp)
154138460Smckusick 	char **cp;
154238460Smckusick 	char **endcp;
154338460Smckusick {
154438460Smckusick 	register char *p;
154538460Smckusick 
154638460Smckusick 	p = *cp;
154738460Smckusick 	while (*p == ' ' || *p == '\t')
154838460Smckusick 		p++;
154951898Smckusick 	if (*p == '\n' || *p == '\0')
155038460Smckusick 		*cp = *endcp = p;
155151898Smckusick 	else {
155251898Smckusick 		*cp = p++;
155351898Smckusick 		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
155451898Smckusick 			p++;
155551898Smckusick 		*endcp = p;
155638460Smckusick 	}
155738460Smckusick }
155839681Smckusick 
155939681Smckusick /*
156051898Smckusick  * Get an exports file line. Skip over blank lines and handle line
156151898Smckusick  * continuations.
156239681Smckusick  */
156351898Smckusick get_line()
156439681Smckusick {
156551898Smckusick 	register char *p, *cp;
156651898Smckusick 	register int len;
156751898Smckusick 	int totlen, cont_line;
156839681Smckusick 
156951898Smckusick 	/*
157051898Smckusick 	 * Loop around ignoring blank lines and getting all continuation lines.
157151898Smckusick 	 */
157251898Smckusick 	p = line;
157351898Smckusick 	totlen = 0;
157451898Smckusick 	do {
157551898Smckusick 		if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
157651898Smckusick 			return (0);
157751898Smckusick 		len = strlen(p);
157851898Smckusick 		cp = p + len - 1;
157951898Smckusick 		cont_line = 0;
158051898Smckusick 		while (cp >= p &&
158151898Smckusick 		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
158251898Smckusick 			if (*cp == '\\')
158351898Smckusick 				cont_line = 1;
158451898Smckusick 			cp--;
158551898Smckusick 			len--;
158651898Smckusick 		}
158751898Smckusick 		*++cp = '\0';
158851898Smckusick 		if (len > 0) {
158951898Smckusick 			totlen += len;
159051898Smckusick 			if (totlen >= LINESIZ) {
159151898Smckusick 				syslog(LOG_ERR, "Exports line too long");
159251898Smckusick 				exit(2);
159351898Smckusick 			}
159451898Smckusick 			p = cp;
159551898Smckusick 		}
159651898Smckusick 	} while (totlen == 0 || cont_line);
159751898Smckusick 	return (1);
159844015Smckusick }
159944015Smckusick 
160051667Smckusick /*
160151667Smckusick  * Parse a description of a credential.
160251667Smckusick  */
160351667Smckusick parsecred(namelist, cr)
160451667Smckusick 	char *namelist;
160551667Smckusick 	register struct ucred *cr;
160651667Smckusick {
160751667Smckusick 	register char *name;
160851667Smckusick 	register int cnt;
160951667Smckusick 	char *names;
161051667Smckusick 	struct passwd *pw;
161151667Smckusick 	struct group *gr;
161251667Smckusick 	int ngroups, groups[NGROUPS + 1];
161351667Smckusick 
161451667Smckusick 	/*
161551667Smckusick 	 * Set up the unpriviledged user.
161651667Smckusick 	 */
161751667Smckusick 	cr->cr_ref = 1;
161851667Smckusick 	cr->cr_uid = -2;
161951667Smckusick 	cr->cr_groups[0] = -2;
162051667Smckusick 	cr->cr_ngroups = 1;
162151667Smckusick 	/*
162251667Smckusick 	 * Get the user's password table entry.
162351667Smckusick 	 */
162451667Smckusick 	names = strsep(&namelist, " \t\n");
162551667Smckusick 	name = strsep(&names, ":");
162651667Smckusick 	if (isdigit(*name) || *name == '-')
162751667Smckusick 		pw = getpwuid(atoi(name));
162851667Smckusick 	else
162951667Smckusick 		pw = getpwnam(name);
163051667Smckusick 	/*
163151667Smckusick 	 * Credentials specified as those of a user.
163251667Smckusick 	 */
163351667Smckusick 	if (names == NULL) {
163451667Smckusick 		if (pw == NULL) {
163551667Smckusick 			syslog(LOG_ERR, "Unknown user: %s\n", name);
163651667Smckusick 			return;
163751667Smckusick 		}
163851667Smckusick 		cr->cr_uid = pw->pw_uid;
163951667Smckusick 		ngroups = NGROUPS + 1;
164051667Smckusick 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
164151667Smckusick 			syslog(LOG_ERR, "Too many groups\n");
164251667Smckusick 		/*
164351667Smckusick 		 * Convert from int's to gid_t's and compress out duplicate
164451667Smckusick 		 */
164551667Smckusick 		cr->cr_ngroups = ngroups - 1;
164651667Smckusick 		cr->cr_groups[0] = groups[0];
164751667Smckusick 		for (cnt = 2; cnt < ngroups; cnt++)
164851667Smckusick 			cr->cr_groups[cnt - 1] = groups[cnt];
164951667Smckusick 		return;
165051667Smckusick 	}
165151667Smckusick 	/*
165251667Smckusick 	 * Explicit credential specified as a colon separated list:
165351667Smckusick 	 *	uid:gid:gid:...
165451667Smckusick 	 */
165551667Smckusick 	if (pw != NULL)
165651667Smckusick 		cr->cr_uid = pw->pw_uid;
165751667Smckusick 	else if (isdigit(*name) || *name == '-')
165851667Smckusick 		cr->cr_uid = atoi(name);
165951667Smckusick 	else {
166051667Smckusick 		syslog(LOG_ERR, "Unknown user: %s\n", name);
166151667Smckusick 		return;
166251667Smckusick 	}
166351667Smckusick 	cr->cr_ngroups = 0;
166451667Smckusick 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
166551667Smckusick 		name = strsep(&names, ":");
166651667Smckusick 		if (isdigit(*name) || *name == '-') {
166751667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
166851667Smckusick 		} else {
166951667Smckusick 			if ((gr = getgrnam(name)) == NULL) {
167051667Smckusick 				syslog(LOG_ERR, "Unknown group: %s\n", name);
167151667Smckusick 				continue;
167251667Smckusick 			}
167351667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
167451667Smckusick 		}
167551667Smckusick 	}
167651667Smckusick 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
167751667Smckusick 		syslog(LOG_ERR, "Too many groups\n");
167851667Smckusick }
167951667Smckusick 
168044015Smckusick #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
168144015Smckusick /*
168244015Smckusick  * Routines that maintain the remote mounttab
168344015Smckusick  */
168451667Smckusick void
168551667Smckusick get_mountlist()
168644015Smckusick {
168744015Smckusick 	register struct mountlist *mlp, **mlpp;
168844015Smckusick 	register char *eos, *dirp;
168944015Smckusick 	int len;
169044015Smckusick 	char str[STRSIZ];
169144015Smckusick 	FILE *mlfile;
169244015Smckusick 
169351712Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
169451667Smckusick 		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
169544015Smckusick 		return;
169644015Smckusick 	}
169744015Smckusick 	mlpp = &mlhead;
169844015Smckusick 	while (fgets(str, STRSIZ, mlfile) != NULL) {
169944015Smckusick 		if ((dirp = index(str, '\t')) == NULL &&
170044015Smckusick 		    (dirp = index(str, ' ')) == NULL)
170144015Smckusick 			continue;
170244015Smckusick 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
170344015Smckusick 		len = dirp-str;
170444015Smckusick 		if (len > RPCMNT_NAMELEN)
170544015Smckusick 			len = RPCMNT_NAMELEN;
170644015Smckusick 		bcopy(str, mlp->ml_host, len);
170744015Smckusick 		mlp->ml_host[len] = '\0';
170844015Smckusick 		while (*dirp == '\t' || *dirp == ' ')
170944015Smckusick 			dirp++;
171044015Smckusick 		if ((eos = index(dirp, '\t')) == NULL &&
171144015Smckusick 		    (eos = index(dirp, ' ')) == NULL &&
171244015Smckusick 		    (eos = index(dirp, '\n')) == NULL)
171344015Smckusick 			len = strlen(dirp);
171444015Smckusick 		else
171544015Smckusick 			len = eos-dirp;
171644015Smckusick 		if (len > RPCMNT_PATHLEN)
171744015Smckusick 			len = RPCMNT_PATHLEN;
171844015Smckusick 		bcopy(dirp, mlp->ml_dirp, len);
171944015Smckusick 		mlp->ml_dirp[len] = '\0';
172044015Smckusick 		mlp->ml_next = (struct mountlist *)0;
172144015Smckusick 		*mlpp = mlp;
172244015Smckusick 		mlpp = &mlp->ml_next;
172344015Smckusick 	}
172444015Smckusick 	fclose(mlfile);
172544015Smckusick }
172644015Smckusick 
172751667Smckusick void
172851667Smckusick del_mlist(hostp, dirp)
172944015Smckusick 	register char *hostp, *dirp;
173044015Smckusick {
173144015Smckusick 	register struct mountlist *mlp, **mlpp;
173251712Smckusick 	struct mountlist *mlp2;
173344015Smckusick 	FILE *mlfile;
173444015Smckusick 	int fnd = 0;
173544015Smckusick 
173644015Smckusick 	mlpp = &mlhead;
173744015Smckusick 	mlp = mlhead;
173844015Smckusick 	while (mlp) {
173944015Smckusick 		if (!strcmp(mlp->ml_host, hostp) &&
174044015Smckusick 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
174144015Smckusick 			fnd = 1;
174251712Smckusick 			mlp2 = mlp;
174351712Smckusick 			*mlpp = mlp = mlp->ml_next;
174451712Smckusick 			free((caddr_t)mlp2);
174551712Smckusick 		} else {
174651712Smckusick 			mlpp = &mlp->ml_next;
174751712Smckusick 			mlp = mlp->ml_next;
174839681Smckusick 		}
174939681Smckusick 	}
175044015Smckusick 	if (fnd) {
175144015Smckusick 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
175251898Smckusick 			syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
175344015Smckusick 			return;
175444015Smckusick 		}
175544015Smckusick 		mlp = mlhead;
175644015Smckusick 		while (mlp) {
175744015Smckusick 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
175844015Smckusick 			mlp = mlp->ml_next;
175944015Smckusick 		}
176044015Smckusick 		fclose(mlfile);
176144015Smckusick 	}
176239681Smckusick }
176344015Smckusick 
176451667Smckusick void
176551667Smckusick add_mlist(hostp, dirp)
176644015Smckusick 	register char *hostp, *dirp;
176744015Smckusick {
176844015Smckusick 	register struct mountlist *mlp, **mlpp;
176944015Smckusick 	FILE *mlfile;
177044015Smckusick 
177144015Smckusick 	mlpp = &mlhead;
177244015Smckusick 	mlp = mlhead;
177344015Smckusick 	while (mlp) {
177444015Smckusick 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
177544015Smckusick 			return;
177644015Smckusick 		mlpp = &mlp->ml_next;
177744015Smckusick 		mlp = mlp->ml_next;
177844015Smckusick 	}
177944015Smckusick 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
178044015Smckusick 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
178144015Smckusick 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
178244015Smckusick 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
178344015Smckusick 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
178444015Smckusick 	mlp->ml_next = (struct mountlist *)0;
178544015Smckusick 	*mlpp = mlp;
178644015Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
178751898Smckusick 		syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
178844015Smckusick 		return;
178944015Smckusick 	}
179044015Smckusick 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
179144015Smckusick 	fclose(mlfile);
179244015Smckusick }
179344015Smckusick 
179444015Smckusick /*
179544015Smckusick  * This function is called via. SIGTERM when the system is going down.
179644015Smckusick  * It sends a broadcast RPCMNT_UMNTALL.
179744015Smckusick  */
179846709Sbostic void
179944015Smckusick send_umntall()
180044015Smckusick {
180144015Smckusick 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
180244015Smckusick 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
180351667Smckusick 	exit(0);
180444015Smckusick }
180544015Smckusick 
180644015Smckusick umntall_each(resultsp, raddr)
180744015Smckusick 	caddr_t resultsp;
180844015Smckusick 	struct sockaddr_in *raddr;
180944015Smckusick {
181044015Smckusick 	return (1);
181144015Smckusick }
181244015Smckusick 
181344015Smckusick /*
181451667Smckusick  * Free up a group list.
181551667Smckusick  */
181651667Smckusick void
181751667Smckusick free_grp(grp)
181851667Smckusick 	register struct grouplist *grp;
181951667Smckusick {
182051667Smckusick 	register char **addrp;
182151667Smckusick 
182251898Smckusick 	if (grp->gr_type == GT_HOST) {
182351712Smckusick 		if (grp->gr_ptr.gt_hostent->h_name) {
182451712Smckusick 			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
182551712Smckusick 			while (addrp && *addrp)
182651712Smckusick 				free(*addrp++);
182751712Smckusick 			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
182851712Smckusick 			free(grp->gr_ptr.gt_hostent->h_name);
182951712Smckusick 		}
183051667Smckusick 		free((caddr_t)grp->gr_ptr.gt_hostent);
183151898Smckusick 	} else if (grp->gr_type == GT_NET) {
183251898Smckusick 		if (grp->gr_ptr.gt_net.nt_name)
183351898Smckusick 			free(grp->gr_ptr.gt_net.nt_name);
183451667Smckusick 	}
183551667Smckusick #ifdef ISO
183651898Smckusick 	else if (grp->gr_type == GT_ISO)
183751667Smckusick 		free((caddr_t)grp->gr_ptr.gt_isoaddr);
183851667Smckusick #endif
183951667Smckusick 	free((caddr_t)grp);
184051667Smckusick }
184151667Smckusick 
184251667Smckusick /*
184351667Smckusick  * char *realpath(const char *path, char resolved_path[MAXPATHLEN])
184451667Smckusick  *
184551667Smckusick  * find the real name of path, by removing all ".", ".."
184651667Smckusick  * and symlink components.
184751667Smckusick  *
184851667Smckusick  * Jan-Simon Pendry, September 1991.
184951667Smckusick  */
185051667Smckusick char *
185151667Smckusick realpath(path, resolved)
185251667Smckusick 	char *path;
185351667Smckusick 	char resolved[MAXPATHLEN];
185451667Smckusick {
185551667Smckusick 	int d = open(".", O_RDONLY);
185651667Smckusick 	int rootd = 0;
185751667Smckusick 	char *p, *q;
185851667Smckusick 	struct stat stb;
185951667Smckusick 	char wbuf[MAXPATHLEN];
186051667Smckusick 
186151667Smckusick 	strcpy(resolved, path);
186251667Smckusick 
186351667Smckusick 	if (d < 0)
186451667Smckusick 		return 0;
186551667Smckusick 
186651667Smckusick loop:;
186751667Smckusick 	q = strrchr(resolved, '/');
186851667Smckusick 	if (q) {
186951667Smckusick 		p = q + 1;
187051667Smckusick 		if (q == resolved)
187151667Smckusick 			q = "/";
187251667Smckusick 		else {
187351667Smckusick 			do
187451667Smckusick 				--q;
187551667Smckusick 			while (q > resolved && *q == '/');
187651667Smckusick 			q[1] = '\0';
187751667Smckusick 			q = resolved;
187851667Smckusick 		}
187951667Smckusick 		if (chdir(q) < 0)
188051667Smckusick 			goto out;
188151667Smckusick 	} else
188251667Smckusick 		p = resolved;
188351667Smckusick 
188451667Smckusick 	if (lstat(p, &stb) == 0) {
188551667Smckusick 		if (S_ISLNK(stb.st_mode)) {
188651667Smckusick 			int n = readlink(p, resolved, MAXPATHLEN);
188751667Smckusick 			if (n < 0)
188851667Smckusick 				goto out;
188951667Smckusick 			resolved[n] = '\0';
189051667Smckusick 			goto loop;
189151667Smckusick 		}
189251667Smckusick 		if (S_ISDIR(stb.st_mode)) {
189351667Smckusick 			if (chdir(p) < 0)
189451667Smckusick 				goto out;
189551667Smckusick 			p = "";
189651667Smckusick 		}
189751667Smckusick 	}
189851667Smckusick 
189951667Smckusick 	strcpy(wbuf, p);
190051667Smckusick 	if (getcwd(resolved, MAXPATHLEN) == 0)
190151667Smckusick 		goto out;
190251667Smckusick 	if (resolved[0] == '/' && resolved[1] == '\0')
190351667Smckusick 		rootd = 1;
190451667Smckusick 
190551667Smckusick 	if (*wbuf) {
190651667Smckusick 		if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) {
190751667Smckusick 			errno = ENAMETOOLONG;
190851667Smckusick 			goto out;
190951667Smckusick 		}
191051667Smckusick 		if (rootd == 0)
191151667Smckusick 			strcat(resolved, "/");
191251667Smckusick 		strcat(resolved, wbuf);
191351667Smckusick 	}
191451667Smckusick 
191551667Smckusick 	if (fchdir(d) < 0)
191651667Smckusick 		goto out;
191751667Smckusick 	(void) close(d);
191851667Smckusick 
191951667Smckusick 	return resolved;
192051667Smckusick 
192151667Smckusick out:;
192251667Smckusick 	(void) close(d);
192351667Smckusick 	return 0;
192451667Smckusick }
192551711Smckusick 
192651711Smckusick #ifdef DEBUG
192751711Smckusick void
192851711Smckusick SYSLOG(int pri, const char *fmt, ...)
192951711Smckusick {
193051711Smckusick 	va_list ap;
193151711Smckusick 
193251711Smckusick 	va_start(ap, fmt);
193351711Smckusick 	vfprintf(stderr, fmt, ap);
193451711Smckusick 	va_end(ap);
193551711Smckusick }
193651711Smckusick #endif /* DEBUG */
193751898Smckusick 
193851898Smckusick /*
193951898Smckusick  * Check options for consistency.
194051898Smckusick  */
194151898Smckusick check_options(dp)
194251898Smckusick 	struct dirlist *dp;
194351898Smckusick {
194451898Smckusick 
194551898Smckusick 	if (dp == (struct dirlist *)0)
194651898Smckusick 	    return (1);
194751898Smckusick 	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
194851898Smckusick 	    (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
194951898Smckusick 	    (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
195051898Smckusick 	    syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
195151898Smckusick 	    return (1);
195251898Smckusick 	}
195351898Smckusick 	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
195451898Smckusick 	    syslog(LOG_ERR, "-mask requires -net");
195551898Smckusick 	    return (1);
195651898Smckusick 	}
195751898Smckusick 	if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
195851898Smckusick 	    syslog(LOG_ERR, "-net and -iso mutually exclusive");
195951898Smckusick 	    return (1);
196051898Smckusick 	}
196151898Smckusick 	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
196251898Smckusick 	    syslog(LOG_ERR, "-alldir has multiple directories");
196351898Smckusick 	    return (1);
196451898Smckusick 	}
196551898Smckusick 	return (0);
196651898Smckusick }
1967