xref: /csrg-svn/sbin/mountd/mountd.c (revision 67383)
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*67383Smkm static char sccsid[] = "@(#)mountd.c	8.9 (Berkeley) 06/14/94";
1938460Smckusick #endif not lint
2038460Smckusick 
2138460Smckusick #include <sys/param.h>
2265863Sbostic #include <sys/file.h>
2338460Smckusick #include <sys/ioctl.h>
2438460Smckusick #include <sys/mount.h>
2538460Smckusick #include <sys/socket.h>
2665863Sbostic #include <sys/stat.h>
2752109Smckusick #include <sys/syslog.h>
2865863Sbostic #include <sys/ucred.h>
2965863Sbostic 
3038460Smckusick #include <rpc/rpc.h>
3138460Smckusick #include <rpc/pmap_clnt.h>
3238460Smckusick #include <rpc/pmap_prot.h>
3351667Smckusick #ifdef ISO
3451667Smckusick #include <netiso/iso.h>
3551667Smckusick #endif
3638460Smckusick #include <nfs/rpcv2.h>
3738460Smckusick #include <nfs/nfsv2.h>
3865863Sbostic 
3966163Spendry #include <arpa/inet.h>
4066163Spendry 
4166163Spendry #include <ctype.h>
4265863Sbostic #include <errno.h>
4365863Sbostic #include <grp.h>
4465863Sbostic #include <netdb.h>
4565863Sbostic #include <pwd.h>
4665863Sbostic #include <signal.h>
4765863Sbostic #include <stdio.h>
4865863Sbostic #include <stdlib.h>
4965863Sbostic #include <string.h>
5065863Sbostic #include <unistd.h>
5165863Sbostic #include "pathnames.h"
5238460Smckusick 
5366163Spendry #ifdef DEBUG
5466163Spendry #include <stdarg.h>
5566163Spendry #endif
5666163Spendry 
5738460Smckusick /*
5838460Smckusick  * Structures for keeping the mount list and export list
5938460Smckusick  */
6038460Smckusick struct mountlist {
6144015Smckusick 	struct mountlist *ml_next;
6238460Smckusick 	char	ml_host[RPCMNT_NAMELEN+1];
6338460Smckusick 	char	ml_dirp[RPCMNT_PATHLEN+1];
6438460Smckusick };
6538460Smckusick 
6651898Smckusick struct dirlist {
6751898Smckusick 	struct dirlist	*dp_left;
6851898Smckusick 	struct dirlist	*dp_right;
6951898Smckusick 	int		dp_flag;
7051898Smckusick 	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
7151898Smckusick 	char		dp_dirp[1];	/* Actually malloc'd to size of dir */
7251898Smckusick };
7351898Smckusick /* dp_flag bits */
7451898Smckusick #define	DP_DEFSET	0x1
7551898Smckusick 
7638460Smckusick struct exportlist {
7738460Smckusick 	struct exportlist *ex_next;
7851898Smckusick 	struct dirlist	*ex_dirl;
7951898Smckusick 	struct dirlist	*ex_defdir;
8051898Smckusick 	int		ex_flag;
8151898Smckusick 	fsid_t		ex_fs;
8251898Smckusick 	char		*ex_fsdir;
8338460Smckusick };
8451898Smckusick /* ex_flag bits */
8552109Smckusick #define	EX_LINKED	0x1
8638460Smckusick 
8751898Smckusick struct netmsk {
8851898Smckusick 	u_long	nt_net;
8951898Smckusick 	u_long	nt_mask;
9051898Smckusick 	char *nt_name;
9151898Smckusick };
9251898Smckusick 
9351667Smckusick union grouptypes {
9451667Smckusick 	struct hostent *gt_hostent;
9551898Smckusick 	struct netmsk	gt_net;
9651667Smckusick #ifdef ISO
9751667Smckusick 	struct sockaddr_iso *gt_isoaddr;
9851667Smckusick #endif
9951667Smckusick };
10051667Smckusick 
10138460Smckusick struct grouplist {
10251898Smckusick 	int gr_type;
10351667Smckusick 	union grouptypes gr_ptr;
10438460Smckusick 	struct grouplist *gr_next;
10538460Smckusick };
10651898Smckusick /* Group types */
10751898Smckusick #define	GT_NULL		0x0
10851898Smckusick #define	GT_HOST		0x1
10951898Smckusick #define	GT_NET		0x2
11051898Smckusick #define	GT_ISO		0x4
11138460Smckusick 
11251898Smckusick struct hostlist {
11351898Smckusick 	struct grouplist *ht_grp;
11451898Smckusick 	struct hostlist	 *ht_next;
11551667Smckusick };
11651667Smckusick 
11738460Smckusick /* Global defs */
11866163Spendry char	*add_expdir __P((struct dirlist **, char *, int));
11966163Spendry void	add_dlist __P((struct dirlist **, struct dirlist *,
12066163Spendry 				struct grouplist *));
12166163Spendry void	add_mlist __P((char *, char *));
12266163Spendry int	check_dirpath __P((char *));
12366163Spendry int	check_options __P((struct dirlist *));
12466163Spendry int	chk_host __P((struct dirlist *, u_long, int *));
12566163Spendry void	del_mlist __P((char *, char *));
12666163Spendry struct dirlist *dirp_search __P((struct dirlist *, char *));
12766163Spendry int	do_mount __P((struct exportlist *, struct grouplist *, int,
12866163Spendry 				struct ucred *, char *, int, struct statfs *));
12966163Spendry int	do_opt __P((char **, char **, struct exportlist *, struct grouplist *,
13066163Spendry 				int *, int *, struct ucred *));
13166163Spendry struct	exportlist *ex_search __P((fsid_t *));
13266163Spendry struct	exportlist *get_exp __P((void));
13366163Spendry void	free_dir __P((struct dirlist *));
13466163Spendry void	free_exp __P((struct exportlist *));
13566163Spendry void	free_grp __P((struct grouplist *));
13666163Spendry void	free_host __P((struct hostlist *));
13766163Spendry void	get_exportlist __P((void));
13866163Spendry int	get_host __P((char *, struct grouplist *));
13966163Spendry struct hostlist *get_ht __P((void));
14066163Spendry int	get_line __P((void));
14166163Spendry void	get_mountlist __P((void));
14266163Spendry int	get_net __P((char *, struct netmsk *, int));
14366163Spendry void	getexp_err __P((struct exportlist *, struct grouplist *));
14466163Spendry struct grouplist *get_grp __P((void));
14566163Spendry void	hang_dirp __P((struct dirlist *, struct grouplist *,
14666163Spendry 				struct exportlist *, int));
14766163Spendry void	mntsrv __P((struct svc_req *, SVCXPRT *));
14866163Spendry void	nextfield __P((char **, char **));
14966163Spendry void	out_of_mem __P((void));
15066163Spendry void	parsecred __P((char *, struct ucred *));
15166163Spendry int	put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *));
15266163Spendry int	scan_tree __P((struct dirlist *, u_long));
15366163Spendry void	send_umntall __P((void));
15466163Spendry int	umntall_each __P((caddr_t, struct sockaddr_in *));
15566163Spendry int	xdr_dir __P((XDR *, char *));
15666163Spendry int	xdr_explist __P((XDR *, caddr_t));
15766163Spendry int	xdr_fhs __P((XDR *, nfsv2fh_t *));
15866163Spendry int	xdr_mlist __P((XDR *, caddr_t));
15966163Spendry 
16066163Spendry /* C library */
16166163Spendry int	getnetgrent();
16266163Spendry void	endnetgrent();
16366163Spendry void	setnetgrent();
16466163Spendry 
16551667Smckusick #ifdef ISO
16651667Smckusick struct iso_addr *iso_addr();
16751667Smckusick #endif
16866163Spendry 
16951898Smckusick struct exportlist *exphead;
17044015Smckusick struct mountlist *mlhead;
17151898Smckusick struct grouplist *grphead;
17238460Smckusick char exname[MAXPATHLEN];
17351667Smckusick struct ucred def_anon = {
17466163Spendry 	1,
17551667Smckusick 	(uid_t) -2,
17651667Smckusick 	1,
17766163Spendry 	{ (gid_t) -2 }
17851667Smckusick };
17944015Smckusick int root_only = 1;
18051898Smckusick int opt_flags;
18151898Smckusick /* Bits for above */
18251898Smckusick #define	OP_MAPROOT	0x01
18351898Smckusick #define	OP_MAPALL	0x02
18451898Smckusick #define	OP_KERB		0x04
18551898Smckusick #define	OP_MASK		0x08
18651898Smckusick #define	OP_NET		0x10
18751898Smckusick #define	OP_ISO		0x20
18851898Smckusick #define	OP_ALLDIRS	0x40
18951898Smckusick 
19038460Smckusick #ifdef DEBUG
19138460Smckusick int debug = 1;
19251711Smckusick void	SYSLOG __P((int, const char *, ...));
19351711Smckusick #define syslog SYSLOG
19438460Smckusick #else
19538460Smckusick int debug = 0;
19638460Smckusick #endif
19738460Smckusick 
19838460Smckusick /*
19938460Smckusick  * Mountd server for NFS mount protocol as described in:
20039681Smckusick  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
20144015Smckusick  * The optional arguments are the exports file name
20239681Smckusick  * default: _PATH_EXPORTS
20344015Smckusick  * and "-n" to allow nonroot mount.
20438460Smckusick  */
20566163Spendry int
20638460Smckusick main(argc, argv)
20738460Smckusick 	int argc;
20844015Smckusick 	char **argv;
20938460Smckusick {
21038460Smckusick 	SVCXPRT *transp;
21144015Smckusick 	int c;
21238460Smckusick 
21344015Smckusick 	while ((c = getopt(argc, argv, "n")) != EOF)
21444015Smckusick 		switch (c) {
21544015Smckusick 		case 'n':
21644015Smckusick 			root_only = 0;
21744015Smckusick 			break;
21844015Smckusick 		default:
21944015Smckusick 			fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
22044015Smckusick 			exit(1);
22144015Smckusick 		};
22244015Smckusick 	argc -= optind;
22344015Smckusick 	argv += optind;
22466163Spendry 	grphead = (struct grouplist *)NULL;
22566163Spendry 	exphead = (struct exportlist *)NULL;
22666163Spendry 	mlhead = (struct mountlist *)NULL;
22744015Smckusick 	if (argc == 1) {
22844015Smckusick 		strncpy(exname, *argv, MAXPATHLEN-1);
22944015Smckusick 		exname[MAXPATHLEN-1] = '\0';
23044015Smckusick 	} else
23144015Smckusick 		strcpy(exname, _PATH_EXPORTS);
23266163Spendry 	openlog("mountd", LOG_PID, LOG_DAEMON);
23351667Smckusick 	if (debug)
23451667Smckusick 		fprintf(stderr,"Getting export list.\n");
23544015Smckusick 	get_exportlist();
23651667Smckusick 	if (debug)
23751667Smckusick 		fprintf(stderr,"Getting mount list.\n");
23844015Smckusick 	get_mountlist();
23951667Smckusick 	if (debug)
24051667Smckusick 		fprintf(stderr,"Here we go.\n");
24138460Smckusick 	if (debug == 0) {
24244690Skarels 		daemon(0, 0);
24338460Smckusick 		signal(SIGINT, SIG_IGN);
24438460Smckusick 		signal(SIGQUIT, SIG_IGN);
24538460Smckusick 	}
24666163Spendry 	signal(SIGHUP, (void (*) __P((int))) get_exportlist);
24766163Spendry 	signal(SIGTERM, (void (*) __P((int))) send_umntall);
24840494Smckusick 	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
24940494Smckusick 	  if (pidfile != NULL) {
25040494Smckusick 		fprintf(pidfile, "%d\n", getpid());
25140494Smckusick 		fclose(pidfile);
25240494Smckusick 	  }
25340494Smckusick 	}
25438460Smckusick 	if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
25538460Smckusick 		syslog(LOG_ERR, "Can't create socket");
25638460Smckusick 		exit(1);
25738460Smckusick 	}
25838460Smckusick 	pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
25951667Smckusick 	if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
26051667Smckusick 	    IPPROTO_UDP)) {
26138460Smckusick 		syslog(LOG_ERR, "Can't register mount");
26238460Smckusick 		exit(1);
26338460Smckusick 	}
26438460Smckusick 	svc_run();
26538460Smckusick 	syslog(LOG_ERR, "Mountd died");
26644690Skarels 	exit(1);
26738460Smckusick }
26838460Smckusick 
26938460Smckusick /*
27038460Smckusick  * The mount rpc service
27138460Smckusick  */
27266163Spendry void
27338460Smckusick mntsrv(rqstp, transp)
27466163Spendry 	struct svc_req *rqstp;
27566163Spendry 	SVCXPRT *transp;
27638460Smckusick {
27766163Spendry 	struct exportlist *ep;
27866163Spendry 	struct dirlist *dp;
27938460Smckusick 	nfsv2fh_t nfh;
28038460Smckusick 	struct authunix_parms *ucr;
28138460Smckusick 	struct stat stb;
28251898Smckusick 	struct statfs fsb;
28338460Smckusick 	struct hostent *hp;
28439681Smckusick 	u_long saddr;
28551667Smckusick 	char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN];
28651898Smckusick 	int bad = ENOENT, omask, defset;
28739681Smckusick 	uid_t uid = -2;
28838460Smckusick 
28938460Smckusick 	/* Get authorization */
29038460Smckusick 	switch (rqstp->rq_cred.oa_flavor) {
29138460Smckusick 	case AUTH_UNIX:
29238460Smckusick 		ucr = (struct authunix_parms *)rqstp->rq_clntcred;
29339681Smckusick 		uid = ucr->aup_uid;
29439681Smckusick 		break;
29538460Smckusick 	case AUTH_NULL:
29638460Smckusick 	default:
29739681Smckusick 		break;
29838460Smckusick 	}
29938460Smckusick 
30039681Smckusick 	saddr = transp->xp_raddr.sin_addr.s_addr;
30166163Spendry 	hp = (struct hostent *)NULL;
30238460Smckusick 	switch (rqstp->rq_proc) {
30339681Smckusick 	case NULLPROC:
30466163Spendry 		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
30539681Smckusick 			syslog(LOG_ERR, "Can't send reply");
30639681Smckusick 		return;
30738460Smckusick 	case RPCMNT_MOUNT:
30851667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
30939681Smckusick 			svcerr_weakauth(transp);
31039681Smckusick 			return;
31139681Smckusick 		}
31251667Smckusick 		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
31338460Smckusick 			svcerr_decode(transp);
31438460Smckusick 			return;
31538460Smckusick 		}
31638460Smckusick 
31751667Smckusick 		/*
31851667Smckusick 		 * Get the real pathname and make sure it is a directory
31951667Smckusick 		 * that exists.
32051667Smckusick 		 */
32151898Smckusick 		if (realpath(rpcpath, dirpath) == 0 ||
32251898Smckusick 		    stat(dirpath, &stb) < 0 ||
323*67383Smkm 		    (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) ||
32451898Smckusick 		    statfs(dirpath, &fsb) < 0) {
32551667Smckusick 			chdir("/");	/* Just in case realpath doesn't */
32651667Smckusick 			if (debug)
32751898Smckusick 				fprintf(stderr, "stat failed on %s\n", dirpath);
32838460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
32938460Smckusick 				syslog(LOG_ERR, "Can't send reply");
33038460Smckusick 			return;
33138460Smckusick 		}
33238460Smckusick 
33338460Smckusick 		/* Check in the exports list */
33438460Smckusick 		omask = sigblock(sigmask(SIGHUP));
33551898Smckusick 		ep = ex_search(&fsb.f_fsid);
33651898Smckusick 		defset = 0;
33751898Smckusick 		if (ep && (chk_host(ep->ex_defdir, saddr, &defset) ||
33851898Smckusick 		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
33951898Smckusick 		     chk_host(dp, saddr, &defset)) ||
34051898Smckusick 		     (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
34151898Smckusick 		      scan_tree(ep->ex_dirl, saddr) == 0))) {
34251667Smckusick 			/* Get the file handle */
34351667Smckusick 			bzero((caddr_t)&nfh, sizeof(nfh));
34451667Smckusick 			if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
34551667Smckusick 				bad = errno;
34651898Smckusick 				syslog(LOG_ERR, "Can't get fh for %s", dirpath);
34751667Smckusick 				if (!svc_sendreply(transp, xdr_long,
34851667Smckusick 				    (caddr_t)&bad))
34951667Smckusick 					syslog(LOG_ERR, "Can't send reply");
35051667Smckusick 				sigsetmask(omask);
35151667Smckusick 				return;
35251667Smckusick 			}
35351667Smckusick 			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
35438460Smckusick 				syslog(LOG_ERR, "Can't send reply");
35551667Smckusick 			if (hp == NULL)
35651667Smckusick 				hp = gethostbyaddr((caddr_t)&saddr,
35751667Smckusick 				    sizeof(saddr), AF_INET);
35851667Smckusick 			if (hp)
35951667Smckusick 				add_mlist(hp->h_name, dirpath);
36051667Smckusick 			else
36151667Smckusick 				add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
36251667Smckusick 					dirpath);
36351667Smckusick 			if (debug)
36451667Smckusick 				fprintf(stderr,"Mount successfull.\n");
36551898Smckusick 		} else {
36651898Smckusick 			bad = EACCES;
36751898Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
36851898Smckusick 				syslog(LOG_ERR, "Can't send reply");
36938460Smckusick 		}
37051667Smckusick 		sigsetmask(omask);
37138460Smckusick 		return;
37238460Smckusick 	case RPCMNT_DUMP:
37366163Spendry 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL))
37438460Smckusick 			syslog(LOG_ERR, "Can't send reply");
37538460Smckusick 		return;
37638460Smckusick 	case RPCMNT_UMOUNT:
37751667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
37839681Smckusick 			svcerr_weakauth(transp);
37939681Smckusick 			return;
38039681Smckusick 		}
38138460Smckusick 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
38238460Smckusick 			svcerr_decode(transp);
38338460Smckusick 			return;
38438460Smckusick 		}
38566163Spendry 		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
38638460Smckusick 			syslog(LOG_ERR, "Can't send reply");
38744015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
38844015Smckusick 		if (hp)
38944015Smckusick 			del_mlist(hp->h_name, dirpath);
39051667Smckusick 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
39138460Smckusick 		return;
39238460Smckusick 	case RPCMNT_UMNTALL:
39351667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
39439681Smckusick 			svcerr_weakauth(transp);
39539681Smckusick 			return;
39639681Smckusick 		}
39766163Spendry 		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
39838460Smckusick 			syslog(LOG_ERR, "Can't send reply");
39944015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
40044015Smckusick 		if (hp)
40166163Spendry 			del_mlist(hp->h_name, (char *)NULL);
40266163Spendry 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL);
40338460Smckusick 		return;
40438460Smckusick 	case RPCMNT_EXPORT:
40566163Spendry 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL))
40638460Smckusick 			syslog(LOG_ERR, "Can't send reply");
40738460Smckusick 		return;
40838460Smckusick 	default:
40938460Smckusick 		svcerr_noproc(transp);
41038460Smckusick 		return;
41138460Smckusick 	}
41238460Smckusick }
41338460Smckusick 
41438460Smckusick /*
41538460Smckusick  * Xdr conversion for a dirpath string
41638460Smckusick  */
41766163Spendry int
41838460Smckusick xdr_dir(xdrsp, dirp)
41938460Smckusick 	XDR *xdrsp;
42038460Smckusick 	char *dirp;
42138460Smckusick {
42238460Smckusick 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
42338460Smckusick }
42438460Smckusick 
42538460Smckusick /*
42638460Smckusick  * Xdr routine to generate fhstatus
42738460Smckusick  */
42866163Spendry int
42938460Smckusick xdr_fhs(xdrsp, nfh)
43038460Smckusick 	XDR *xdrsp;
43138460Smckusick 	nfsv2fh_t *nfh;
43238460Smckusick {
43338460Smckusick 	int ok = 0;
43438460Smckusick 
43538460Smckusick 	if (!xdr_long(xdrsp, &ok))
43638460Smckusick 		return (0);
43738460Smckusick 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
43838460Smckusick }
43938460Smckusick 
44066163Spendry int
44138460Smckusick xdr_mlist(xdrsp, cp)
44238460Smckusick 	XDR *xdrsp;
44338460Smckusick 	caddr_t cp;
44438460Smckusick {
44566163Spendry 	struct mountlist *mlp;
44638460Smckusick 	int true = 1;
44738460Smckusick 	int false = 0;
44838460Smckusick 	char *strp;
44938460Smckusick 
45044015Smckusick 	mlp = mlhead;
45144015Smckusick 	while (mlp) {
45244015Smckusick 		if (!xdr_bool(xdrsp, &true))
45344015Smckusick 			return (0);
45444015Smckusick 		strp = &mlp->ml_host[0];
45544015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
45644015Smckusick 			return (0);
45744015Smckusick 		strp = &mlp->ml_dirp[0];
45844015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
45944015Smckusick 			return (0);
46044015Smckusick 		mlp = mlp->ml_next;
46138460Smckusick 	}
46238460Smckusick 	if (!xdr_bool(xdrsp, &false))
46338460Smckusick 		return (0);
46438460Smckusick 	return (1);
46538460Smckusick }
46638460Smckusick 
46738460Smckusick /*
46838460Smckusick  * Xdr conversion for export list
46938460Smckusick  */
47066163Spendry int
47138460Smckusick xdr_explist(xdrsp, cp)
47238460Smckusick 	XDR *xdrsp;
47338460Smckusick 	caddr_t cp;
47438460Smckusick {
47566163Spendry 	struct exportlist *ep;
47638460Smckusick 	int false = 0;
47764903Smckusick 	int omask, putdef;
47838460Smckusick 
47938460Smckusick 	omask = sigblock(sigmask(SIGHUP));
48051898Smckusick 	ep = exphead;
48151898Smckusick 	while (ep) {
48264903Smckusick 		putdef = 0;
48364903Smckusick 		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef))
48438460Smckusick 			goto errout;
48564903Smckusick 		if (ep->ex_defdir && putdef == 0 &&
48666163Spendry 			put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL,
48764903Smckusick 			&putdef))
48864903Smckusick 			goto errout;
48938460Smckusick 		ep = ep->ex_next;
49038460Smckusick 	}
49138460Smckusick 	sigsetmask(omask);
49238460Smckusick 	if (!xdr_bool(xdrsp, &false))
49338460Smckusick 		return (0);
49438460Smckusick 	return (1);
49538460Smckusick errout:
49638460Smckusick 	sigsetmask(omask);
49738460Smckusick 	return (0);
49838460Smckusick }
49938460Smckusick 
50051898Smckusick /*
50151898Smckusick  * Called from xdr_explist() to traverse the tree and export the
50251898Smckusick  * directory paths.
50351898Smckusick  */
50466163Spendry int
50564903Smckusick put_exlist(dp, xdrsp, adp, putdefp)
50666163Spendry 	struct dirlist *dp;
50751898Smckusick 	XDR *xdrsp;
50851898Smckusick 	struct dirlist *adp;
50964903Smckusick 	int *putdefp;
51051898Smckusick {
51166163Spendry 	struct grouplist *grp;
51266163Spendry 	struct hostlist *hp;
51351898Smckusick 	int true = 1;
51451898Smckusick 	int false = 0;
51551898Smckusick 	int gotalldir = 0;
51651898Smckusick 	char *strp;
51751898Smckusick 
51851898Smckusick 	if (dp) {
51964903Smckusick 		if (put_exlist(dp->dp_left, xdrsp, adp, putdefp))
52051898Smckusick 			return (1);
52151898Smckusick 		if (!xdr_bool(xdrsp, &true))
52251898Smckusick 			return (1);
52351898Smckusick 		strp = dp->dp_dirp;
52451898Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
52551898Smckusick 			return (1);
52664903Smckusick 		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
52751898Smckusick 			gotalldir = 1;
52864903Smckusick 			*putdefp = 1;
52964903Smckusick 		}
53051898Smckusick 		if ((dp->dp_flag & DP_DEFSET) == 0 &&
53151898Smckusick 		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
53251898Smckusick 			hp = dp->dp_hosts;
53351898Smckusick 			while (hp) {
53451898Smckusick 				grp = hp->ht_grp;
53551898Smckusick 				if (grp->gr_type == GT_HOST) {
53651898Smckusick 					if (!xdr_bool(xdrsp, &true))
53751898Smckusick 						return (1);
53851898Smckusick 					strp = grp->gr_ptr.gt_hostent->h_name;
53951898Smckusick 					if (!xdr_string(xdrsp, &strp,
54051898Smckusick 					    RPCMNT_NAMELEN))
54151898Smckusick 						return (1);
54251898Smckusick 				} else if (grp->gr_type == GT_NET) {
54351898Smckusick 					if (!xdr_bool(xdrsp, &true))
54451898Smckusick 						return (1);
54551898Smckusick 					strp = grp->gr_ptr.gt_net.nt_name;
54651898Smckusick 					if (!xdr_string(xdrsp, &strp,
54751898Smckusick 					    RPCMNT_NAMELEN))
54851898Smckusick 						return (1);
54951898Smckusick 				}
55051898Smckusick 				hp = hp->ht_next;
55166163Spendry 				if (gotalldir && hp == (struct hostlist *)NULL) {
55251898Smckusick 					hp = adp->dp_hosts;
55351898Smckusick 					gotalldir = 0;
55451898Smckusick 				}
55551898Smckusick 			}
55651898Smckusick 		}
55751898Smckusick 		if (!xdr_bool(xdrsp, &false))
55851898Smckusick 			return (1);
55964903Smckusick 		if (put_exlist(dp->dp_right, xdrsp, adp, putdefp))
56051898Smckusick 			return (1);
56151898Smckusick 	}
56251898Smckusick 	return (0);
56351898Smckusick }
56451898Smckusick 
56538460Smckusick #define LINESIZ	10240
56638460Smckusick char line[LINESIZ];
56751898Smckusick FILE *exp_file;
56838460Smckusick 
56938460Smckusick /*
57038460Smckusick  * Get the export list
57138460Smckusick  */
57246709Sbostic void
57338460Smckusick get_exportlist()
57438460Smckusick {
57566163Spendry 	struct exportlist *ep, *ep2;
57666163Spendry 	struct grouplist *grp, *tgrp;
57751898Smckusick 	struct exportlist **epp;
57851898Smckusick 	struct dirlist *dirhead;
57952109Smckusick 	struct statfs fsb, *fsp;
58051898Smckusick 	struct hostent *hpe;
58151898Smckusick 	struct ucred anon;
58253150Smckusick 	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
58353150Smckusick 	int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
58438460Smckusick 
58538460Smckusick 	/*
58638460Smckusick 	 * First, get rid of the old list
58738460Smckusick 	 */
58851898Smckusick 	ep = exphead;
58951898Smckusick 	while (ep) {
59038460Smckusick 		ep2 = ep;
59138460Smckusick 		ep = ep->ex_next;
59244015Smckusick 		free_exp(ep2);
59338460Smckusick 	}
59466163Spendry 	exphead = (struct exportlist *)NULL;
59538460Smckusick 
59651898Smckusick 	grp = grphead;
59751898Smckusick 	while (grp) {
59851898Smckusick 		tgrp = grp;
59951898Smckusick 		grp = grp->gr_next;
60051898Smckusick 		free_grp(tgrp);
60151667Smckusick 	}
60266163Spendry 	grphead = (struct grouplist *)NULL;
60351667Smckusick 
60438460Smckusick 	/*
60552109Smckusick 	 * And delete exports that are in the kernel for all local
60652109Smckusick 	 * file systems.
60752109Smckusick 	 * XXX: Should know how to handle all local exportable file systems
60852109Smckusick 	 *      instead of just MOUNT_UFS.
60952109Smckusick 	 */
61053214Smckusick 	num = getmntinfo(&fsp, MNT_NOWAIT);
61152109Smckusick 	for (i = 0; i < num; i++) {
61265713Shibler 		union {
61365713Shibler 			struct ufs_args ua;
61465713Shibler 			struct iso_args ia;
61565713Shibler 			struct mfs_args ma;
61665713Shibler 		} targs;
61765713Shibler 
61865713Shibler 		switch (fsp->f_type) {
61965863Sbostic 		case MOUNT_MFS:
62065713Shibler 		case MOUNT_UFS:
62165863Sbostic 		case MOUNT_CD9660:
62265863Sbostic 			targs.ua.fspec = NULL;
62365713Shibler 			targs.ua.export.ex_flags = MNT_DELEXPORT;
62452109Smckusick 			if (mount(fsp->f_type, fsp->f_mntonname,
62565713Shibler 				  fsp->f_flags | MNT_UPDATE,
62665713Shibler 				  (caddr_t)&targs) < 0)
62765713Shibler 				syslog(LOG_ERR, "Can't delete exports for %s",
62852109Smckusick 				       fsp->f_mntonname);
62952109Smckusick 		}
63052109Smckusick 		fsp++;
63152109Smckusick 	}
63252109Smckusick 
63352109Smckusick 	/*
63438460Smckusick 	 * Read in the exports file and build the list, calling
63551667Smckusick 	 * mount() as we go along to push the export rules into the kernel.
63638460Smckusick 	 */
63751898Smckusick 	if ((exp_file = fopen(exname, "r")) == NULL) {
63838460Smckusick 		syslog(LOG_ERR, "Can't open %s", exname);
63938460Smckusick 		exit(2);
64038460Smckusick 	}
64166163Spendry 	dirhead = (struct dirlist *)NULL;
64251898Smckusick 	while (get_line()) {
64351667Smckusick 		if (debug)
64451667Smckusick 			fprintf(stderr,"Got line %s\n",line);
64538460Smckusick 		cp = line;
64638460Smckusick 		nextfield(&cp, &endcp);
64751667Smckusick 		if (*cp == '#')
64851667Smckusick 			goto nextline;
64951898Smckusick 
65051898Smckusick 		/*
65151898Smckusick 		 * Set defaults.
65251898Smckusick 		 */
65351898Smckusick 		has_host = FALSE;
65451898Smckusick 		anon = def_anon;
65551667Smckusick 		exflags = MNT_EXPORTED;
65651898Smckusick 		got_nondir = 0;
65751898Smckusick 		opt_flags = 0;
65866163Spendry 		ep = (struct exportlist *)NULL;
65944015Smckusick 
66044015Smckusick 		/*
66144015Smckusick 		 * Create new exports list entry
66244015Smckusick 		 */
66338460Smckusick 		len = endcp-cp;
66453150Smckusick 		tgrp = grp = get_grp();
66551898Smckusick 		while (len > 0) {
66651898Smckusick 			if (len > RPCMNT_NAMELEN) {
66753150Smckusick 			    getexp_err(ep, tgrp);
66851898Smckusick 			    goto nextline;
66951667Smckusick 			}
67045271Smckusick 			if (*cp == '-') {
67166163Spendry 			    if (ep == (struct exportlist *)NULL) {
67253150Smckusick 				getexp_err(ep, tgrp);
67351898Smckusick 				goto nextline;
67451898Smckusick 			    }
67551898Smckusick 			    if (debug)
67651898Smckusick 				fprintf(stderr, "doing opt %s\n", cp);
67751898Smckusick 			    got_nondir = 1;
67851898Smckusick 			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
67951898Smckusick 				&exflags, &anon)) {
68053150Smckusick 				getexp_err(ep, tgrp);
68151898Smckusick 				goto nextline;
68251898Smckusick 			    }
68351898Smckusick 			} else if (*cp == '/') {
68451898Smckusick 			    savedc = *endcp;
68551898Smckusick 			    *endcp = '\0';
68665940Sbostic 			    if (check_dirpath(cp) &&
68751898Smckusick 				statfs(cp, &fsb) >= 0) {
68851898Smckusick 				if (got_nondir) {
68951898Smckusick 				    syslog(LOG_ERR, "Dirs must be first");
69053150Smckusick 				    getexp_err(ep, tgrp);
69151898Smckusick 				    goto nextline;
69251898Smckusick 				}
69351898Smckusick 				if (ep) {
69451898Smckusick 				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
69551898Smckusick 					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
69653150Smckusick 					getexp_err(ep, tgrp);
69751898Smckusick 					goto nextline;
69851898Smckusick 				    }
69951667Smckusick 				} else {
70051898Smckusick 				    /*
70151898Smckusick 				     * See if this directory is already
70251898Smckusick 				     * in the list.
70351898Smckusick 				     */
70451898Smckusick 				    ep = ex_search(&fsb.f_fsid);
70566163Spendry 				    if (ep == (struct exportlist *)NULL) {
70651898Smckusick 					ep = get_exp();
70751898Smckusick 					ep->ex_fs = fsb.f_fsid;
70851898Smckusick 					ep->ex_fsdir = (char *)
70951898Smckusick 					    malloc(strlen(fsb.f_mntonname) + 1);
71051898Smckusick 					if (ep->ex_fsdir)
71151898Smckusick 					    strcpy(ep->ex_fsdir,
71251898Smckusick 						fsb.f_mntonname);
71351898Smckusick 					else
71451898Smckusick 					    out_of_mem();
71551898Smckusick 					if (debug)
71651898Smckusick 					  fprintf(stderr,
71751898Smckusick 					      "Making new ep fs=0x%x,0x%x\n",
71851898Smckusick 					      fsb.f_fsid.val[0],
71951898Smckusick 					      fsb.f_fsid.val[1]);
72051898Smckusick 				    } else if (debug)
72151898Smckusick 					fprintf(stderr,
72251898Smckusick 					    "Found ep fs=0x%x,0x%x\n",
72351898Smckusick 					    fsb.f_fsid.val[0],
72451898Smckusick 					    fsb.f_fsid.val[1]);
72538460Smckusick 				}
72651898Smckusick 
72751898Smckusick 				/*
72851898Smckusick 				 * Add dirpath to export mount point.
72951898Smckusick 				 */
73051898Smckusick 				dirp = add_expdir(&dirhead, cp, len);
73151898Smckusick 				dirplen = len;
73251898Smckusick 			    } else {
73353150Smckusick 				getexp_err(ep, tgrp);
73451898Smckusick 				goto nextline;
73551898Smckusick 			    }
73651898Smckusick 			    *endcp = savedc;
73751898Smckusick 			} else {
73851898Smckusick 			    savedc = *endcp;
73951898Smckusick 			    *endcp = '\0';
74051898Smckusick 			    got_nondir = 1;
74166163Spendry 			    if (ep == (struct exportlist *)NULL) {
74253150Smckusick 				getexp_err(ep, tgrp);
74351898Smckusick 				goto nextline;
74451898Smckusick 			    }
74553150Smckusick 
74653150Smckusick 			    /*
74753150Smckusick 			     * Get the host or netgroup.
74853150Smckusick 			     */
74953150Smckusick 			    setnetgrent(cp);
75053150Smckusick 			    netgrp = getnetgrent(&hst, &usr, &dom);
75153150Smckusick 			    do {
75253150Smckusick 				if (has_host) {
75353150Smckusick 				    grp->gr_next = get_grp();
75453150Smckusick 				    grp = grp->gr_next;
75553150Smckusick 				}
75653150Smckusick 				if (netgrp) {
75753150Smckusick 				    if (get_host(hst, grp)) {
75853150Smckusick 					syslog(LOG_ERR, "Bad netgroup %s", cp);
75953150Smckusick 					getexp_err(ep, tgrp);
76053150Smckusick 					goto nextline;
76153150Smckusick 				    }
76253150Smckusick 				} else if (get_host(cp, grp)) {
76353150Smckusick 				    getexp_err(ep, tgrp);
76453150Smckusick 				    goto nextline;
76553150Smckusick 				}
76653150Smckusick 				has_host = TRUE;
76753150Smckusick 			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
76853150Smckusick 			    endnetgrent();
76951898Smckusick 			    *endcp = savedc;
77038460Smckusick 			}
77138460Smckusick 			cp = endcp;
77238460Smckusick 			nextfield(&cp, &endcp);
77345271Smckusick 			len = endcp - cp;
77438460Smckusick 		}
77551898Smckusick 		if (check_options(dirhead)) {
77653150Smckusick 			getexp_err(ep, tgrp);
77751898Smckusick 			goto nextline;
77851898Smckusick 		}
77951898Smckusick 		if (!has_host) {
78051898Smckusick 			grp->gr_type = GT_HOST;
78151667Smckusick 			if (debug)
78251667Smckusick 				fprintf(stderr,"Adding a default entry\n");
78351667Smckusick 			/* add a default group and make the grp list NULL */
78451667Smckusick 			hpe = (struct hostent *)malloc(sizeof(struct hostent));
78566163Spendry 			if (hpe == (struct hostent *)NULL)
78651898Smckusick 				out_of_mem();
78751898Smckusick 			hpe->h_name = "Default";
78851667Smckusick 			hpe->h_addrtype = AF_INET;
78951667Smckusick 			hpe->h_length = sizeof (u_long);
79066163Spendry 			hpe->h_addr_list = (char **)NULL;
79151898Smckusick 			grp->gr_ptr.gt_hostent = hpe;
79253150Smckusick 
79353150Smckusick 		/*
79453150Smckusick 		 * Don't allow a network export coincide with a list of
79553150Smckusick 		 * host(s) on the same line.
79653150Smckusick 		 */
79753150Smckusick 		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
79853150Smckusick 			getexp_err(ep, tgrp);
79953150Smckusick 			goto nextline;
80051667Smckusick 		}
80153150Smckusick 
80253150Smckusick 		/*
80353150Smckusick 		 * Loop through hosts, pushing the exports into the kernel.
80453150Smckusick 		 * After loop, tgrp points to the start of the list and
80553150Smckusick 		 * grp points to the last entry in the list.
80653150Smckusick 		 */
80753150Smckusick 		grp = tgrp;
80853150Smckusick 		do {
80953150Smckusick 		    if (do_mount(ep, grp, exflags, &anon, dirp,
81051898Smckusick 			dirplen, &fsb)) {
81153150Smckusick 			getexp_err(ep, tgrp);
81251898Smckusick 			goto nextline;
81353150Smckusick 		    }
81453150Smckusick 		} while (grp->gr_next && (grp = grp->gr_next));
81551898Smckusick 
81651898Smckusick 		/*
81751898Smckusick 		 * Success. Update the data structures.
81851898Smckusick 		 */
81951898Smckusick 		if (has_host) {
82053150Smckusick 			hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS));
82151898Smckusick 			grp->gr_next = grphead;
82253150Smckusick 			grphead = tgrp;
82351898Smckusick 		} else {
82466163Spendry 			hang_dirp(dirhead, (struct grouplist *)NULL, ep,
82553150Smckusick 			(opt_flags & OP_ALLDIRS));
82651898Smckusick 			free_grp(grp);
82751898Smckusick 		}
82866163Spendry 		dirhead = (struct dirlist *)NULL;
82951898Smckusick 		if ((ep->ex_flag & EX_LINKED) == 0) {
83051898Smckusick 			ep2 = exphead;
83151898Smckusick 			epp = &exphead;
83251898Smckusick 
83351898Smckusick 			/*
83451898Smckusick 			 * Insert in the list in alphabetical order.
83551898Smckusick 			 */
83651898Smckusick 			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
83751898Smckusick 				epp = &ep2->ex_next;
83851898Smckusick 				ep2 = ep2->ex_next;
83951898Smckusick 			}
84051898Smckusick 			if (ep2)
84151898Smckusick 				ep->ex_next = ep2;
84251898Smckusick 			*epp = ep;
84351898Smckusick 			ep->ex_flag |= EX_LINKED;
84451898Smckusick 		}
84551898Smckusick nextline:
84651898Smckusick 		if (dirhead) {
84751898Smckusick 			free_dir(dirhead);
84866163Spendry 			dirhead = (struct dirlist *)NULL;
84951898Smckusick 		}
85051898Smckusick 	}
85151898Smckusick 	fclose(exp_file);
85251898Smckusick }
85351898Smckusick 
85451898Smckusick /*
85551898Smckusick  * Allocate an export list element
85651898Smckusick  */
85751898Smckusick struct exportlist *
85851898Smckusick get_exp()
85951898Smckusick {
86066163Spendry 	struct exportlist *ep;
86151898Smckusick 
86251898Smckusick 	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
86366163Spendry 	if (ep == (struct exportlist *)NULL)
86451898Smckusick 		out_of_mem();
86551898Smckusick 	bzero((caddr_t)ep, sizeof (struct exportlist));
86651898Smckusick 	return (ep);
86751898Smckusick }
86851898Smckusick 
86951898Smckusick /*
87051898Smckusick  * Allocate a group list element
87151898Smckusick  */
87251898Smckusick struct grouplist *
87351898Smckusick get_grp()
87451898Smckusick {
87566163Spendry 	struct grouplist *gp;
87651898Smckusick 
87751898Smckusick 	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
87866163Spendry 	if (gp == (struct grouplist *)NULL)
87951898Smckusick 		out_of_mem();
88051898Smckusick 	bzero((caddr_t)gp, sizeof (struct grouplist));
88151898Smckusick 	return (gp);
88251898Smckusick }
88351898Smckusick 
88451898Smckusick /*
88551898Smckusick  * Clean up upon an error in get_exportlist().
88651898Smckusick  */
88751898Smckusick void
88851898Smckusick getexp_err(ep, grp)
88951898Smckusick 	struct exportlist *ep;
89051898Smckusick 	struct grouplist *grp;
89151898Smckusick {
89253150Smckusick 	struct grouplist *tgrp;
89351898Smckusick 
89451898Smckusick 	syslog(LOG_ERR, "Bad exports list line %s", line);
89559017Smckusick 	if (ep && (ep->ex_flag & EX_LINKED) == 0)
89651898Smckusick 		free_exp(ep);
89753150Smckusick 	while (grp) {
89853150Smckusick 		tgrp = grp;
89953150Smckusick 		grp = grp->gr_next;
90053150Smckusick 		free_grp(tgrp);
90153150Smckusick 	}
90251898Smckusick }
90351898Smckusick 
90451898Smckusick /*
90551898Smckusick  * Search the export list for a matching fs.
90651898Smckusick  */
90751898Smckusick struct exportlist *
90851898Smckusick ex_search(fsid)
90952109Smckusick 	fsid_t *fsid;
91051898Smckusick {
91166163Spendry 	struct exportlist *ep;
91251898Smckusick 
91351898Smckusick 	ep = exphead;
91451898Smckusick 	while (ep) {
91551898Smckusick 		if (ep->ex_fs.val[0] == fsid->val[0] &&
91651898Smckusick 		    ep->ex_fs.val[1] == fsid->val[1])
91751898Smckusick 			return (ep);
91851898Smckusick 		ep = ep->ex_next;
91951898Smckusick 	}
92051898Smckusick 	return (ep);
92151898Smckusick }
92251898Smckusick 
92351898Smckusick /*
92451898Smckusick  * Add a directory path to the list.
92551898Smckusick  */
92651898Smckusick char *
92751898Smckusick add_expdir(dpp, cp, len)
92851898Smckusick 	struct dirlist **dpp;
92951898Smckusick 	char *cp;
93051898Smckusick 	int len;
93151898Smckusick {
93266163Spendry 	struct dirlist *dp;
93351898Smckusick 
93451898Smckusick 	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
93551898Smckusick 	dp->dp_left = *dpp;
93666163Spendry 	dp->dp_right = (struct dirlist *)NULL;
93751898Smckusick 	dp->dp_flag = 0;
93866163Spendry 	dp->dp_hosts = (struct hostlist *)NULL;
93951898Smckusick 	strcpy(dp->dp_dirp, cp);
94051898Smckusick 	*dpp = dp;
94151898Smckusick 	return (dp->dp_dirp);
94251898Smckusick }
94351898Smckusick 
94451898Smckusick /*
94551898Smckusick  * Hang the dir list element off the dirpath binary tree as required
94651898Smckusick  * and update the entry for host.
94751898Smckusick  */
94851898Smckusick void
94951898Smckusick hang_dirp(dp, grp, ep, alldirs)
95066163Spendry 	struct dirlist *dp;
95151898Smckusick 	struct grouplist *grp;
95251898Smckusick 	struct exportlist *ep;
95351898Smckusick 	int alldirs;
95451898Smckusick {
95566163Spendry 	struct hostlist *hp;
95651898Smckusick 	struct dirlist *dp2;
95751898Smckusick 
95851898Smckusick 	if (alldirs) {
95951898Smckusick 		if (ep->ex_defdir)
96051898Smckusick 			free((caddr_t)dp);
96151898Smckusick 		else
96251898Smckusick 			ep->ex_defdir = dp;
96366163Spendry 		if (grp == (struct grouplist *)NULL)
96455292Smckusick 			ep->ex_defdir->dp_flag |= DP_DEFSET;
96555292Smckusick 		else while (grp) {
96651898Smckusick 			hp = get_ht();
96751898Smckusick 			hp->ht_grp = grp;
96851898Smckusick 			hp->ht_next = ep->ex_defdir->dp_hosts;
96951898Smckusick 			ep->ex_defdir->dp_hosts = hp;
97055292Smckusick 			grp = grp->gr_next;
97155292Smckusick 		}
97251898Smckusick 	} else {
97353150Smckusick 
97453150Smckusick 		/*
97553150Smckusick 		 * Loop throught the directories adding them to the tree.
97653150Smckusick 		 */
97751898Smckusick 		while (dp) {
97851898Smckusick 			dp2 = dp->dp_left;
97953150Smckusick 			add_dlist(&ep->ex_dirl, dp, grp);
98051898Smckusick 			dp = dp2;
98151898Smckusick 		}
98251898Smckusick 	}
98351898Smckusick }
98451898Smckusick 
98551898Smckusick /*
98651898Smckusick  * Traverse the binary tree either updating a node that is already there
98751898Smckusick  * for the new directory or adding the new node.
98851898Smckusick  */
98951898Smckusick void
99053150Smckusick add_dlist(dpp, newdp, grp)
99151898Smckusick 	struct dirlist **dpp;
99251898Smckusick 	struct dirlist *newdp;
99366163Spendry 	struct grouplist *grp;
99451898Smckusick {
99566163Spendry 	struct dirlist *dp;
99666163Spendry 	struct hostlist *hp;
99751898Smckusick 	int cmp;
99851898Smckusick 
99951898Smckusick 	dp = *dpp;
100051898Smckusick 	if (dp) {
100151898Smckusick 		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
100251898Smckusick 		if (cmp > 0) {
100353150Smckusick 			add_dlist(&dp->dp_left, newdp, grp);
100451898Smckusick 			return;
100551898Smckusick 		} else if (cmp < 0) {
100653150Smckusick 			add_dlist(&dp->dp_right, newdp, grp);
100751898Smckusick 			return;
100851898Smckusick 		} else
100951898Smckusick 			free((caddr_t)newdp);
101051898Smckusick 	} else {
101151898Smckusick 		dp = newdp;
101266163Spendry 		dp->dp_left = (struct dirlist *)NULL;
101351898Smckusick 		*dpp = dp;
101451898Smckusick 	}
101553150Smckusick 	if (grp) {
101653150Smckusick 
101753150Smckusick 		/*
101853150Smckusick 		 * Hang all of the host(s) off of the directory point.
101953150Smckusick 		 */
102053150Smckusick 		do {
102153150Smckusick 			hp = get_ht();
102253150Smckusick 			hp->ht_grp = grp;
102353150Smckusick 			hp->ht_next = dp->dp_hosts;
102453150Smckusick 			dp->dp_hosts = hp;
102553150Smckusick 			grp = grp->gr_next;
102653150Smckusick 		} while (grp);
102751898Smckusick 	} else
102851898Smckusick 		dp->dp_flag |= DP_DEFSET;
102951898Smckusick }
103051898Smckusick 
103151898Smckusick /*
103251898Smckusick  * Search for a dirpath on the export point.
103351898Smckusick  */
103451898Smckusick struct dirlist *
103551898Smckusick dirp_search(dp, dirpath)
103666163Spendry 	struct dirlist *dp;
103751898Smckusick 	char *dirpath;
103851898Smckusick {
103966163Spendry 	int cmp;
104051898Smckusick 
104151898Smckusick 	if (dp) {
104251898Smckusick 		cmp = strcmp(dp->dp_dirp, dirpath);
104351898Smckusick 		if (cmp > 0)
104451898Smckusick 			return (dirp_search(dp->dp_left, dirpath));
104551898Smckusick 		else if (cmp < 0)
104651898Smckusick 			return (dirp_search(dp->dp_right, dirpath));
104751898Smckusick 		else
104851898Smckusick 			return (dp);
104951898Smckusick 	}
105051898Smckusick 	return (dp);
105151898Smckusick }
105251898Smckusick 
105351898Smckusick /*
105451898Smckusick  * Scan for a host match in a directory tree.
105551898Smckusick  */
105666163Spendry int
105751898Smckusick chk_host(dp, saddr, defsetp)
105851898Smckusick 	struct dirlist *dp;
105951898Smckusick 	u_long saddr;
106051898Smckusick 	int *defsetp;
106151898Smckusick {
106266163Spendry 	struct hostlist *hp;
106366163Spendry 	struct grouplist *grp;
106466163Spendry 	u_long **addrp;
106551898Smckusick 
106651898Smckusick 	if (dp) {
106751898Smckusick 		if (dp->dp_flag & DP_DEFSET)
106851898Smckusick 			*defsetp = 1;
106951898Smckusick 		hp = dp->dp_hosts;
107051898Smckusick 		while (hp) {
107151898Smckusick 			grp = hp->ht_grp;
107251898Smckusick 			switch (grp->gr_type) {
107351898Smckusick 			case GT_HOST:
107451898Smckusick 			    addrp = (u_long **)
107551898Smckusick 				grp->gr_ptr.gt_hostent->h_addr_list;
107651898Smckusick 			    while (*addrp) {
107751898Smckusick 				if (**addrp == saddr)
107851898Smckusick 				    return (1);
107951898Smckusick 				addrp++;
108051898Smckusick 			    }
108151898Smckusick 			    break;
108251898Smckusick 			case GT_NET:
108351898Smckusick 			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
108451898Smckusick 				grp->gr_ptr.gt_net.nt_net)
108551898Smckusick 				return (1);
108651898Smckusick 			    break;
108751898Smckusick 			};
108851898Smckusick 			hp = hp->ht_next;
108951898Smckusick 		}
109051898Smckusick 	}
109151898Smckusick 	return (0);
109251898Smckusick }
109351898Smckusick 
109451898Smckusick /*
109551898Smckusick  * Scan tree for a host that matches the address.
109651898Smckusick  */
109766163Spendry int
109851898Smckusick scan_tree(dp, saddr)
109966163Spendry 	struct dirlist *dp;
110051898Smckusick 	u_long saddr;
110151898Smckusick {
110251898Smckusick 	int defset;
110351898Smckusick 
110451898Smckusick 	if (dp) {
110551898Smckusick 		if (scan_tree(dp->dp_left, saddr))
110651898Smckusick 			return (1);
110751898Smckusick 		if (chk_host(dp, saddr, &defset))
110851898Smckusick 			return (1);
110951898Smckusick 		if (scan_tree(dp->dp_right, saddr))
111051898Smckusick 			return (1);
111151898Smckusick 	}
111251898Smckusick 	return (0);
111351898Smckusick }
111451898Smckusick 
111551898Smckusick /*
111651898Smckusick  * Traverse the dirlist tree and free it up.
111751898Smckusick  */
111851898Smckusick void
111951898Smckusick free_dir(dp)
112066163Spendry 	struct dirlist *dp;
112151898Smckusick {
112251898Smckusick 
112351898Smckusick 	if (dp) {
112451898Smckusick 		free_dir(dp->dp_left);
112551898Smckusick 		free_dir(dp->dp_right);
112651898Smckusick 		free_host(dp->dp_hosts);
112751898Smckusick 		free((caddr_t)dp);
112851898Smckusick 	}
112951898Smckusick }
113051898Smckusick 
113151898Smckusick /*
113251898Smckusick  * Parse the option string and update fields.
113351898Smckusick  * Option arguments may either be -<option>=<value> or
113451898Smckusick  * -<option> <value>
113551898Smckusick  */
113666163Spendry int
113751898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
113851898Smckusick 	char **cpp, **endcpp;
113951898Smckusick 	struct exportlist *ep;
114051898Smckusick 	struct grouplist *grp;
114151898Smckusick 	int *has_hostp;
114251898Smckusick 	int *exflagsp;
114351898Smckusick 	struct ucred *cr;
114451898Smckusick {
114566163Spendry 	char *cpoptarg, *cpoptend;
114651898Smckusick 	char *cp, *endcp, *cpopt, savedc, savedc2;
114751898Smckusick 	int allflag, usedarg;
114851898Smckusick 
114951898Smckusick 	cpopt = *cpp;
115051898Smckusick 	cpopt++;
115151898Smckusick 	cp = *endcpp;
115251898Smckusick 	savedc = *cp;
115351898Smckusick 	*cp = '\0';
115451898Smckusick 	while (cpopt && *cpopt) {
115551898Smckusick 		allflag = 1;
115651898Smckusick 		usedarg = -2;
115751898Smckusick 		if (cpoptend = index(cpopt, ',')) {
115851898Smckusick 			*cpoptend++ = '\0';
115951898Smckusick 			if (cpoptarg = index(cpopt, '='))
116051898Smckusick 				*cpoptarg++ = '\0';
116151898Smckusick 		} else {
116251898Smckusick 			if (cpoptarg = index(cpopt, '='))
116351898Smckusick 				*cpoptarg++ = '\0';
116451898Smckusick 			else {
116551898Smckusick 				*cp = savedc;
116651898Smckusick 				nextfield(&cp, &endcp);
116751898Smckusick 				**endcpp = '\0';
116851898Smckusick 				if (endcp > cp && *cp != '-') {
116951898Smckusick 					cpoptarg = cp;
117051898Smckusick 					savedc2 = *endcp;
117151898Smckusick 					*endcp = '\0';
117251898Smckusick 					usedarg = 0;
117351667Smckusick 				}
117451667Smckusick 			}
117551667Smckusick 		}
117651898Smckusick 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
117751898Smckusick 			*exflagsp |= MNT_EXRDONLY;
117851898Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
117951898Smckusick 		    !(allflag = strcmp(cpopt, "mapall")) ||
118051898Smckusick 		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
118151898Smckusick 			usedarg++;
118251898Smckusick 			parsecred(cpoptarg, cr);
118351898Smckusick 			if (allflag == 0) {
118451898Smckusick 				*exflagsp |= MNT_EXPORTANON;
118551898Smckusick 				opt_flags |= OP_MAPALL;
118651898Smckusick 			} else
118751898Smckusick 				opt_flags |= OP_MAPROOT;
118851898Smckusick 		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
118951898Smckusick 			*exflagsp |= MNT_EXKERB;
119051898Smckusick 			opt_flags |= OP_KERB;
119153150Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
119253150Smckusick 			!strcmp(cpopt, "m"))) {
119351898Smckusick 			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
119451898Smckusick 				syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
119551898Smckusick 				return (1);
119651898Smckusick 			}
119751898Smckusick 			usedarg++;
119851898Smckusick 			opt_flags |= OP_MASK;
119953150Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
120053150Smckusick 			!strcmp(cpopt, "n"))) {
120151898Smckusick 			if (grp->gr_type != GT_NULL) {
120251898Smckusick 				syslog(LOG_ERR, "Network/host conflict");
120351898Smckusick 				return (1);
120451898Smckusick 			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
120551898Smckusick 				syslog(LOG_ERR, "Bad net: %s", cpoptarg);
120651898Smckusick 				return (1);
120751898Smckusick 			}
120851898Smckusick 			grp->gr_type = GT_NET;
120951898Smckusick 			*has_hostp = 1;
121051898Smckusick 			usedarg++;
121151898Smckusick 			opt_flags |= OP_NET;
121251898Smckusick 		} else if (!strcmp(cpopt, "alldirs")) {
121351898Smckusick 			opt_flags |= OP_ALLDIRS;
121451898Smckusick #ifdef ISO
121551898Smckusick 		} else if (cpoptarg && !strcmp(cpopt, "iso")) {
121651898Smckusick 			if (get_isoaddr(cpoptarg, grp)) {
121751898Smckusick 				syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
121851898Smckusick 				return (1);
121951898Smckusick 			}
122051898Smckusick 			*has_hostp = 1;
122151898Smckusick 			usedarg++;
122251898Smckusick 			opt_flags |= OP_ISO;
122351898Smckusick #endif /* ISO */
122451898Smckusick 		} else {
122551898Smckusick 			syslog(LOG_ERR, "Bad opt %s", cpopt);
122651898Smckusick 			return (1);
122751667Smckusick 		}
122851898Smckusick 		if (usedarg >= 0) {
122951898Smckusick 			*endcp = savedc2;
123051898Smckusick 			**endcpp = savedc;
123151898Smckusick 			if (usedarg > 0) {
123251898Smckusick 				*cpp = cp;
123351898Smckusick 				*endcpp = endcp;
123451898Smckusick 			}
123551898Smckusick 			return (0);
123651898Smckusick 		}
123751898Smckusick 		cpopt = cpoptend;
123851667Smckusick 	}
123951898Smckusick 	**endcpp = savedc;
124051898Smckusick 	return (0);
124151898Smckusick }
124251898Smckusick 
124351898Smckusick /*
124451898Smckusick  * Translate a character string to the corresponding list of network
124551898Smckusick  * addresses for a hostname.
124651898Smckusick  */
124766163Spendry int
124851898Smckusick get_host(cp, grp)
124951898Smckusick 	char *cp;
125066163Spendry 	struct grouplist *grp;
125151898Smckusick {
125266163Spendry 	struct hostent *hp, *nhp;
125366163Spendry 	char **addrp, **naddrp;
125451898Smckusick 	struct hostent t_host;
125551898Smckusick 	int i;
125651898Smckusick 	u_long saddr;
125751898Smckusick 	char *aptr[2];
125851898Smckusick 
125951898Smckusick 	if (grp->gr_type != GT_NULL)
126051898Smckusick 		return (1);
126151898Smckusick 	if ((hp = gethostbyname(cp)) == NULL) {
126251898Smckusick 		if (isdigit(*cp)) {
126351898Smckusick 			saddr = inet_addr(cp);
126451898Smckusick 			if (saddr == -1) {
126551898Smckusick 				syslog(LOG_ERR, "Inet_addr failed");
126651898Smckusick 				return (1);
126751898Smckusick 			}
126851898Smckusick 			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
126951898Smckusick 				AF_INET)) == NULL) {
127051898Smckusick 				hp = &t_host;
127151898Smckusick 				hp->h_name = cp;
127251898Smckusick 				hp->h_addrtype = AF_INET;
127351898Smckusick 				hp->h_length = sizeof (u_long);
127451898Smckusick 				hp->h_addr_list = aptr;
127551898Smckusick 				aptr[0] = (char *)&saddr;
127666163Spendry 				aptr[1] = (char *)NULL;
127751898Smckusick 			}
127851898Smckusick 		} else {
127951898Smckusick 			syslog(LOG_ERR, "Gethostbyname failed");
128051898Smckusick 			return (1);
128151898Smckusick 		}
128251898Smckusick 	}
128351898Smckusick 	grp->gr_type = GT_HOST;
128451898Smckusick 	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
128551898Smckusick 		malloc(sizeof(struct hostent));
128666163Spendry 	if (nhp == (struct hostent *)NULL)
128751898Smckusick 		out_of_mem();
128851898Smckusick 	bcopy((caddr_t)hp, (caddr_t)nhp,
128951898Smckusick 		sizeof(struct hostent));
129051898Smckusick 	i = strlen(hp->h_name)+1;
129151898Smckusick 	nhp->h_name = (char *)malloc(i);
129266163Spendry 	if (nhp->h_name == (char *)NULL)
129351898Smckusick 		out_of_mem();
129451898Smckusick 	bcopy(hp->h_name, nhp->h_name, i);
129551898Smckusick 	addrp = hp->h_addr_list;
129651898Smckusick 	i = 1;
129751898Smckusick 	while (*addrp++)
129851898Smckusick 		i++;
129951898Smckusick 	naddrp = nhp->h_addr_list = (char **)
130051898Smckusick 		malloc(i*sizeof(char *));
130166163Spendry 	if (naddrp == (char **)NULL)
130251898Smckusick 		out_of_mem();
130351898Smckusick 	addrp = hp->h_addr_list;
130451898Smckusick 	while (*addrp) {
130551898Smckusick 		*naddrp = (char *)
130651898Smckusick 		    malloc(hp->h_length);
130766163Spendry 		if (*naddrp == (char *)NULL)
130851898Smckusick 		    out_of_mem();
130951898Smckusick 		bcopy(*addrp, *naddrp,
131051898Smckusick 			hp->h_length);
131151898Smckusick 		addrp++;
131251898Smckusick 		naddrp++;
131351898Smckusick 	}
131466163Spendry 	*naddrp = (char *)NULL;
131553150Smckusick 	if (debug)
131653150Smckusick 		fprintf(stderr, "got host %s\n", hp->h_name);
131751898Smckusick 	return (0);
131851898Smckusick }
131951898Smckusick 
132051898Smckusick /*
132151898Smckusick  * Free up an exports list component
132251898Smckusick  */
132351898Smckusick void
132451898Smckusick free_exp(ep)
132566163Spendry 	struct exportlist *ep;
132651898Smckusick {
132751898Smckusick 
132851898Smckusick 	if (ep->ex_defdir) {
132951898Smckusick 		free_host(ep->ex_defdir->dp_hosts);
133051898Smckusick 		free((caddr_t)ep->ex_defdir);
133151898Smckusick 	}
133251898Smckusick 	if (ep->ex_fsdir)
133351898Smckusick 		free(ep->ex_fsdir);
133451898Smckusick 	free_dir(ep->ex_dirl);
133551898Smckusick 	free((caddr_t)ep);
133651898Smckusick }
133751898Smckusick 
133851898Smckusick /*
133951898Smckusick  * Free hosts.
134051898Smckusick  */
134151898Smckusick void
134251898Smckusick free_host(hp)
134366163Spendry 	struct hostlist *hp;
134451898Smckusick {
134566163Spendry 	struct hostlist *hp2;
134651898Smckusick 
134751898Smckusick 	while (hp) {
134851898Smckusick 		hp2 = hp;
134951898Smckusick 		hp = hp->ht_next;
135051898Smckusick 		free((caddr_t)hp2);
135151898Smckusick 	}
135251898Smckusick }
135351898Smckusick 
135451898Smckusick struct hostlist *
135551898Smckusick get_ht()
135651898Smckusick {
135766163Spendry 	struct hostlist *hp;
135851898Smckusick 
135951898Smckusick 	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
136066163Spendry 	if (hp == (struct hostlist *)NULL)
136151898Smckusick 		out_of_mem();
136266163Spendry 	hp->ht_next = (struct hostlist *)NULL;
136351898Smckusick 	return (hp);
136451898Smckusick }
136551898Smckusick 
136651898Smckusick #ifdef ISO
136751898Smckusick /*
136851898Smckusick  * Translate an iso address.
136951898Smckusick  */
137051898Smckusick get_isoaddr(cp, grp)
137151898Smckusick 	char *cp;
137251898Smckusick 	struct grouplist *grp;
137351898Smckusick {
137451898Smckusick 	struct iso_addr *isop;
137551898Smckusick 	struct sockaddr_iso *isoaddr;
137651898Smckusick 
137751898Smckusick 	if (grp->gr_type != GT_NULL)
137851898Smckusick 		return (1);
137951898Smckusick 	if ((isop = iso_addr(cp)) == NULL) {
138051898Smckusick 		syslog(LOG_ERR,
138151898Smckusick 		    "iso_addr failed, ignored");
138251898Smckusick 		return (1);
138351898Smckusick 	}
138451898Smckusick 	isoaddr = (struct sockaddr_iso *)
138551898Smckusick 	    malloc(sizeof (struct sockaddr_iso));
138666163Spendry 	if (isoaddr == (struct sockaddr_iso *)NULL)
138751898Smckusick 		out_of_mem();
138851898Smckusick 	bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
138951898Smckusick 	bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr,
139051898Smckusick 		sizeof (struct iso_addr));
139151898Smckusick 	isoaddr->siso_len = sizeof (struct sockaddr_iso);
139251898Smckusick 	isoaddr->siso_family = AF_ISO;
139351898Smckusick 	grp->gr_type = GT_ISO;
139451898Smckusick 	grp->gr_ptr.gt_isoaddr = isoaddr;
139551898Smckusick 	return (0);
139651898Smckusick }
139751898Smckusick #endif	/* ISO */
139851898Smckusick 
139951898Smckusick /*
140051898Smckusick  * Out of memory, fatal
140151898Smckusick  */
140251898Smckusick void
140351898Smckusick out_of_mem()
140451898Smckusick {
140551898Smckusick 
140651898Smckusick 	syslog(LOG_ERR, "Out of memory");
140751667Smckusick 	exit(2);
140851667Smckusick }
140951667Smckusick 
141051898Smckusick /*
141151898Smckusick  * Do the mount syscall with the update flag to push the export info into
141251898Smckusick  * the kernel.
141351898Smckusick  */
141466163Spendry int
141551898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
141651667Smckusick 	struct exportlist *ep;
141751667Smckusick 	struct grouplist *grp;
141851898Smckusick 	int exflags;
141951667Smckusick 	struct ucred *anoncrp;
142051898Smckusick 	char *dirp;
142151898Smckusick 	int dirplen;
142251898Smckusick 	struct statfs *fsb;
142351667Smckusick {
142466163Spendry 	char *cp = (char *)NULL;
142566163Spendry 	u_long **addrp;
142651898Smckusick 	int done;
142766163Spendry 	char savedc = '\0';
142851898Smckusick 	struct sockaddr_in sin, imask;
142965713Shibler 	union {
143065713Shibler 		struct ufs_args ua;
143165713Shibler 		struct iso_args ia;
143265713Shibler 		struct mfs_args ma;
143365713Shibler 	} args;
143451898Smckusick 	u_long net;
143551667Smckusick 
143665713Shibler 	args.ua.fspec = 0;
143765713Shibler 	args.ua.export.ex_flags = exflags;
143865713Shibler 	args.ua.export.ex_anon = *anoncrp;
143955878Smckusick 	bzero((char *)&sin, sizeof(sin));
144055878Smckusick 	bzero((char *)&imask, sizeof(imask));
144151667Smckusick 	sin.sin_family = AF_INET;
144251667Smckusick 	sin.sin_len = sizeof(sin);
144351898Smckusick 	imask.sin_family = AF_INET;
144451898Smckusick 	imask.sin_len = sizeof(sin);
144551898Smckusick 	if (grp->gr_type == GT_HOST)
144651667Smckusick 		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
144751898Smckusick 	else
144866163Spendry 		addrp = (u_long **)NULL;
144951667Smckusick 	done = FALSE;
145051898Smckusick 	while (!done) {
145151898Smckusick 		switch (grp->gr_type) {
145251898Smckusick 		case GT_HOST:
145364903Smckusick 			if (addrp) {
145451712Smckusick 				sin.sin_addr.s_addr = **addrp;
145565713Shibler 				args.ua.export.ex_addrlen = sizeof(sin);
145664903Smckusick 			} else
145765713Shibler 				args.ua.export.ex_addrlen = 0;
145865713Shibler 			args.ua.export.ex_addr = (struct sockaddr *)&sin;
145965713Shibler 			args.ua.export.ex_masklen = 0;
146051898Smckusick 			break;
146151898Smckusick 		case GT_NET:
146251898Smckusick 			if (grp->gr_ptr.gt_net.nt_mask)
146351898Smckusick 			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
146451898Smckusick 			else {
146551898Smckusick 			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
146651898Smckusick 			    if (IN_CLASSA(net))
146751898Smckusick 				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
146851898Smckusick 			    else if (IN_CLASSB(net))
146951898Smckusick 				imask.sin_addr.s_addr =
147051898Smckusick 				    inet_addr("255.255.0.0");
147151898Smckusick 			    else
147251898Smckusick 				imask.sin_addr.s_addr =
147351898Smckusick 				    inet_addr("255.255.255.0");
147451898Smckusick 			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
147551898Smckusick 			}
147651898Smckusick 			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
147765713Shibler 			args.ua.export.ex_addr = (struct sockaddr *)&sin;
147865713Shibler 			args.ua.export.ex_addrlen = sizeof (sin);
147965713Shibler 			args.ua.export.ex_mask = (struct sockaddr *)&imask;
148065713Shibler 			args.ua.export.ex_masklen = sizeof (imask);
148151898Smckusick 			break;
148251667Smckusick #ifdef ISO
148351898Smckusick 		case GT_ISO:
148465713Shibler 			args.ua.export.ex_addr =
148565713Shibler 				(struct sockaddr *)grp->gr_ptr.gt_isoaddr;
148665713Shibler 			args.ua.export.ex_addrlen =
148765713Shibler 				sizeof(struct sockaddr_iso);
148865713Shibler 			args.ua.export.ex_masklen = 0;
148951898Smckusick 			break;
149051667Smckusick #endif	/* ISO */
149151898Smckusick 		default:
149251667Smckusick 			syslog(LOG_ERR, "Bad grouptype");
149351898Smckusick 			if (cp)
149451898Smckusick 				*cp = savedc;
149551898Smckusick 			return (1);
149651898Smckusick 		};
149752109Smckusick 
149852109Smckusick 		/*
149952109Smckusick 		 * XXX:
150052109Smckusick 		 * Maybe I should just use the fsb->f_mntonname path instead
150152109Smckusick 		 * of looping back up the dirp to the mount point??
150252109Smckusick 		 * Also, needs to know how to export all types of local
150352109Smckusick 		 * exportable file systems and not just MOUNT_UFS.
150452109Smckusick 		 */
150552109Smckusick 		while (mount(fsb->f_type, dirp,
150652109Smckusick 		       fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
150751898Smckusick 			if (cp)
150851898Smckusick 				*cp-- = savedc;
150951898Smckusick 			else
151051898Smckusick 				cp = dirp + dirplen - 1;
151151667Smckusick 			if (errno == EPERM) {
151251667Smckusick 				syslog(LOG_ERR,
151351898Smckusick 				   "Can't change attributes for %s.\n", dirp);
151451898Smckusick 				return (1);
151551667Smckusick 			}
151651898Smckusick 			if (opt_flags & OP_ALLDIRS) {
151751898Smckusick 				syslog(LOG_ERR, "Not root dir");
151851898Smckusick 				return (1);
151951898Smckusick 			}
152051667Smckusick 			/* back up over the last component */
152151898Smckusick 			while (*cp == '/' && cp > dirp)
152251667Smckusick 				cp--;
152351898Smckusick 			while (*(cp - 1) != '/' && cp > dirp)
152451667Smckusick 				cp--;
152551898Smckusick 			if (cp == dirp) {
152651898Smckusick 				if (debug)
152751667Smckusick 					fprintf(stderr,"mnt unsucc\n");
152851898Smckusick 				syslog(LOG_ERR, "Can't export %s", dirp);
152951898Smckusick 				return (1);
153051667Smckusick 			}
153151667Smckusick 			savedc = *cp;
153251667Smckusick 			*cp = '\0';
153351667Smckusick 		}
153451898Smckusick 		if (addrp) {
153551667Smckusick 			++addrp;
153666163Spendry 			if (*addrp == (u_long *)NULL)
153751667Smckusick 				done = TRUE;
153851898Smckusick 		} else
153951898Smckusick 			done = TRUE;
154051898Smckusick 	}
154151898Smckusick 	if (cp)
154251898Smckusick 		*cp = savedc;
154351898Smckusick 	return (0);
154451898Smckusick }
154551898Smckusick 
154651898Smckusick /*
154751898Smckusick  * Translate a net address.
154851898Smckusick  */
154966163Spendry int
155051898Smckusick get_net(cp, net, maskflg)
155151898Smckusick 	char *cp;
155251898Smckusick 	struct netmsk *net;
155351898Smckusick 	int maskflg;
155451898Smckusick {
155566163Spendry 	struct netent *np;
155666163Spendry 	long netaddr;
155751898Smckusick 	struct in_addr inetaddr, inetaddr2;
155851898Smckusick 	char *name;
155951898Smckusick 
156051898Smckusick 	if (np = getnetbyname(cp))
156151898Smckusick 		inetaddr = inet_makeaddr(np->n_net, 0);
156251898Smckusick 	else if (isdigit(*cp)) {
156351898Smckusick 		if ((netaddr = inet_network(cp)) == -1)
156451898Smckusick 			return (1);
156551898Smckusick 		inetaddr = inet_makeaddr(netaddr, 0);
156651898Smckusick 		/*
156751898Smckusick 		 * Due to arbritrary subnet masks, you don't know how many
156851898Smckusick 		 * bits to shift the address to make it into a network,
156951898Smckusick 		 * however you do know how to make a network address into
157051898Smckusick 		 * a host with host == 0 and then compare them.
157151898Smckusick 		 * (What a pest)
157251898Smckusick 		 */
157351898Smckusick 		if (!maskflg) {
157451898Smckusick 			setnetent(0);
157551898Smckusick 			while (np = getnetent()) {
157651898Smckusick 				inetaddr2 = inet_makeaddr(np->n_net, 0);
157751898Smckusick 				if (inetaddr2.s_addr == inetaddr.s_addr)
157851898Smckusick 					break;
157951898Smckusick 			}
158051898Smckusick 			endnetent();
158151667Smckusick 		}
158251898Smckusick 	} else
158351898Smckusick 		return (1);
158451898Smckusick 	if (maskflg)
158551898Smckusick 		net->nt_mask = inetaddr.s_addr;
158651898Smckusick 	else {
158751898Smckusick 		if (np)
158851898Smckusick 			name = np->n_name;
158951898Smckusick 		else
159051898Smckusick 			name = inet_ntoa(inetaddr);
159151898Smckusick 		net->nt_name = (char *)malloc(strlen(name) + 1);
159266163Spendry 		if (net->nt_name == (char *)NULL)
159351898Smckusick 			out_of_mem();
159451898Smckusick 		strcpy(net->nt_name, name);
159551898Smckusick 		net->nt_net = inetaddr.s_addr;
159638460Smckusick 	}
159751898Smckusick 	return (0);
159838460Smckusick }
159938460Smckusick 
160038460Smckusick /*
160138460Smckusick  * Parse out the next white space separated field
160238460Smckusick  */
160351667Smckusick void
160438460Smckusick nextfield(cp, endcp)
160538460Smckusick 	char **cp;
160638460Smckusick 	char **endcp;
160738460Smckusick {
160866163Spendry 	char *p;
160938460Smckusick 
161038460Smckusick 	p = *cp;
161138460Smckusick 	while (*p == ' ' || *p == '\t')
161238460Smckusick 		p++;
161351898Smckusick 	if (*p == '\n' || *p == '\0')
161438460Smckusick 		*cp = *endcp = p;
161551898Smckusick 	else {
161651898Smckusick 		*cp = p++;
161751898Smckusick 		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
161851898Smckusick 			p++;
161951898Smckusick 		*endcp = p;
162038460Smckusick 	}
162138460Smckusick }
162239681Smckusick 
162339681Smckusick /*
162451898Smckusick  * Get an exports file line. Skip over blank lines and handle line
162551898Smckusick  * continuations.
162639681Smckusick  */
162766163Spendry int
162851898Smckusick get_line()
162939681Smckusick {
163066163Spendry 	char *p, *cp;
163166163Spendry 	int len;
163251898Smckusick 	int totlen, cont_line;
163339681Smckusick 
163451898Smckusick 	/*
163551898Smckusick 	 * Loop around ignoring blank lines and getting all continuation lines.
163651898Smckusick 	 */
163751898Smckusick 	p = line;
163851898Smckusick 	totlen = 0;
163951898Smckusick 	do {
164051898Smckusick 		if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
164151898Smckusick 			return (0);
164251898Smckusick 		len = strlen(p);
164351898Smckusick 		cp = p + len - 1;
164451898Smckusick 		cont_line = 0;
164551898Smckusick 		while (cp >= p &&
164651898Smckusick 		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
164751898Smckusick 			if (*cp == '\\')
164851898Smckusick 				cont_line = 1;
164951898Smckusick 			cp--;
165051898Smckusick 			len--;
165151898Smckusick 		}
165251898Smckusick 		*++cp = '\0';
165351898Smckusick 		if (len > 0) {
165451898Smckusick 			totlen += len;
165551898Smckusick 			if (totlen >= LINESIZ) {
165651898Smckusick 				syslog(LOG_ERR, "Exports line too long");
165751898Smckusick 				exit(2);
165851898Smckusick 			}
165951898Smckusick 			p = cp;
166051898Smckusick 		}
166151898Smckusick 	} while (totlen == 0 || cont_line);
166251898Smckusick 	return (1);
166344015Smckusick }
166444015Smckusick 
166551667Smckusick /*
166651667Smckusick  * Parse a description of a credential.
166751667Smckusick  */
166866163Spendry void
166951667Smckusick parsecred(namelist, cr)
167051667Smckusick 	char *namelist;
167166163Spendry 	struct ucred *cr;
167251667Smckusick {
167366163Spendry 	char *name;
167466163Spendry 	int cnt;
167551667Smckusick 	char *names;
167651667Smckusick 	struct passwd *pw;
167751667Smckusick 	struct group *gr;
167851667Smckusick 	int ngroups, groups[NGROUPS + 1];
167951667Smckusick 
168051667Smckusick 	/*
168151667Smckusick 	 * Set up the unpriviledged user.
168251667Smckusick 	 */
168351667Smckusick 	cr->cr_ref = 1;
168451667Smckusick 	cr->cr_uid = -2;
168551667Smckusick 	cr->cr_groups[0] = -2;
168651667Smckusick 	cr->cr_ngroups = 1;
168751667Smckusick 	/*
168851667Smckusick 	 * Get the user's password table entry.
168951667Smckusick 	 */
169051667Smckusick 	names = strsep(&namelist, " \t\n");
169151667Smckusick 	name = strsep(&names, ":");
169251667Smckusick 	if (isdigit(*name) || *name == '-')
169351667Smckusick 		pw = getpwuid(atoi(name));
169451667Smckusick 	else
169551667Smckusick 		pw = getpwnam(name);
169651667Smckusick 	/*
169751667Smckusick 	 * Credentials specified as those of a user.
169851667Smckusick 	 */
169951667Smckusick 	if (names == NULL) {
170051667Smckusick 		if (pw == NULL) {
170166163Spendry 			syslog(LOG_ERR, "Unknown user: %s", name);
170251667Smckusick 			return;
170351667Smckusick 		}
170451667Smckusick 		cr->cr_uid = pw->pw_uid;
170551667Smckusick 		ngroups = NGROUPS + 1;
170651667Smckusick 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
170766163Spendry 			syslog(LOG_ERR, "Too many groups");
170851667Smckusick 		/*
170951667Smckusick 		 * Convert from int's to gid_t's and compress out duplicate
171051667Smckusick 		 */
171151667Smckusick 		cr->cr_ngroups = ngroups - 1;
171251667Smckusick 		cr->cr_groups[0] = groups[0];
171351667Smckusick 		for (cnt = 2; cnt < ngroups; cnt++)
171451667Smckusick 			cr->cr_groups[cnt - 1] = groups[cnt];
171551667Smckusick 		return;
171651667Smckusick 	}
171751667Smckusick 	/*
171851667Smckusick 	 * Explicit credential specified as a colon separated list:
171951667Smckusick 	 *	uid:gid:gid:...
172051667Smckusick 	 */
172151667Smckusick 	if (pw != NULL)
172251667Smckusick 		cr->cr_uid = pw->pw_uid;
172351667Smckusick 	else if (isdigit(*name) || *name == '-')
172451667Smckusick 		cr->cr_uid = atoi(name);
172551667Smckusick 	else {
172666163Spendry 		syslog(LOG_ERR, "Unknown user: %s", name);
172751667Smckusick 		return;
172851667Smckusick 	}
172951667Smckusick 	cr->cr_ngroups = 0;
173051667Smckusick 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
173151667Smckusick 		name = strsep(&names, ":");
173251667Smckusick 		if (isdigit(*name) || *name == '-') {
173351667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
173451667Smckusick 		} else {
173551667Smckusick 			if ((gr = getgrnam(name)) == NULL) {
173666163Spendry 				syslog(LOG_ERR, "Unknown group: %s", name);
173751667Smckusick 				continue;
173851667Smckusick 			}
173951667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
174051667Smckusick 		}
174151667Smckusick 	}
174251667Smckusick 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
174366163Spendry 		syslog(LOG_ERR, "Too many groups");
174451667Smckusick }
174551667Smckusick 
174644015Smckusick #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
174744015Smckusick /*
174844015Smckusick  * Routines that maintain the remote mounttab
174944015Smckusick  */
175051667Smckusick void
175151667Smckusick get_mountlist()
175244015Smckusick {
175366163Spendry 	struct mountlist *mlp, **mlpp;
175466163Spendry 	char *eos, *dirp;
175544015Smckusick 	int len;
175644015Smckusick 	char str[STRSIZ];
175744015Smckusick 	FILE *mlfile;
175844015Smckusick 
175951712Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
176051667Smckusick 		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
176144015Smckusick 		return;
176244015Smckusick 	}
176344015Smckusick 	mlpp = &mlhead;
176444015Smckusick 	while (fgets(str, STRSIZ, mlfile) != NULL) {
176544015Smckusick 		if ((dirp = index(str, '\t')) == NULL &&
176644015Smckusick 		    (dirp = index(str, ' ')) == NULL)
176744015Smckusick 			continue;
176844015Smckusick 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
176944015Smckusick 		len = dirp-str;
177044015Smckusick 		if (len > RPCMNT_NAMELEN)
177144015Smckusick 			len = RPCMNT_NAMELEN;
177244015Smckusick 		bcopy(str, mlp->ml_host, len);
177344015Smckusick 		mlp->ml_host[len] = '\0';
177444015Smckusick 		while (*dirp == '\t' || *dirp == ' ')
177544015Smckusick 			dirp++;
177644015Smckusick 		if ((eos = index(dirp, '\t')) == NULL &&
177744015Smckusick 		    (eos = index(dirp, ' ')) == NULL &&
177844015Smckusick 		    (eos = index(dirp, '\n')) == NULL)
177944015Smckusick 			len = strlen(dirp);
178044015Smckusick 		else
178144015Smckusick 			len = eos-dirp;
178244015Smckusick 		if (len > RPCMNT_PATHLEN)
178344015Smckusick 			len = RPCMNT_PATHLEN;
178444015Smckusick 		bcopy(dirp, mlp->ml_dirp, len);
178544015Smckusick 		mlp->ml_dirp[len] = '\0';
178666163Spendry 		mlp->ml_next = (struct mountlist *)NULL;
178744015Smckusick 		*mlpp = mlp;
178844015Smckusick 		mlpp = &mlp->ml_next;
178944015Smckusick 	}
179044015Smckusick 	fclose(mlfile);
179144015Smckusick }
179244015Smckusick 
179351667Smckusick void
179451667Smckusick del_mlist(hostp, dirp)
179566163Spendry 	char *hostp, *dirp;
179644015Smckusick {
179766163Spendry 	struct mountlist *mlp, **mlpp;
179851712Smckusick 	struct mountlist *mlp2;
179944015Smckusick 	FILE *mlfile;
180044015Smckusick 	int fnd = 0;
180144015Smckusick 
180244015Smckusick 	mlpp = &mlhead;
180344015Smckusick 	mlp = mlhead;
180444015Smckusick 	while (mlp) {
180544015Smckusick 		if (!strcmp(mlp->ml_host, hostp) &&
180644015Smckusick 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
180744015Smckusick 			fnd = 1;
180851712Smckusick 			mlp2 = mlp;
180951712Smckusick 			*mlpp = mlp = mlp->ml_next;
181051712Smckusick 			free((caddr_t)mlp2);
181151712Smckusick 		} else {
181251712Smckusick 			mlpp = &mlp->ml_next;
181351712Smckusick 			mlp = mlp->ml_next;
181439681Smckusick 		}
181539681Smckusick 	}
181644015Smckusick 	if (fnd) {
181744015Smckusick 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
181851898Smckusick 			syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
181944015Smckusick 			return;
182044015Smckusick 		}
182144015Smckusick 		mlp = mlhead;
182244015Smckusick 		while (mlp) {
182344015Smckusick 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
182444015Smckusick 			mlp = mlp->ml_next;
182544015Smckusick 		}
182644015Smckusick 		fclose(mlfile);
182744015Smckusick 	}
182839681Smckusick }
182944015Smckusick 
183051667Smckusick void
183151667Smckusick add_mlist(hostp, dirp)
183266163Spendry 	char *hostp, *dirp;
183344015Smckusick {
183466163Spendry 	struct mountlist *mlp, **mlpp;
183544015Smckusick 	FILE *mlfile;
183644015Smckusick 
183744015Smckusick 	mlpp = &mlhead;
183844015Smckusick 	mlp = mlhead;
183944015Smckusick 	while (mlp) {
184044015Smckusick 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
184144015Smckusick 			return;
184244015Smckusick 		mlpp = &mlp->ml_next;
184344015Smckusick 		mlp = mlp->ml_next;
184444015Smckusick 	}
184544015Smckusick 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
184644015Smckusick 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
184744015Smckusick 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
184844015Smckusick 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
184944015Smckusick 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
185066163Spendry 	mlp->ml_next = (struct mountlist *)NULL;
185144015Smckusick 	*mlpp = mlp;
185244015Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
185351898Smckusick 		syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
185444015Smckusick 		return;
185544015Smckusick 	}
185644015Smckusick 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
185744015Smckusick 	fclose(mlfile);
185844015Smckusick }
185944015Smckusick 
186044015Smckusick /*
186144015Smckusick  * This function is called via. SIGTERM when the system is going down.
186244015Smckusick  * It sends a broadcast RPCMNT_UMNTALL.
186344015Smckusick  */
186446709Sbostic void
186544015Smckusick send_umntall()
186644015Smckusick {
186744015Smckusick 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
186844015Smckusick 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
186951667Smckusick 	exit(0);
187044015Smckusick }
187144015Smckusick 
187266163Spendry int
187344015Smckusick umntall_each(resultsp, raddr)
187444015Smckusick 	caddr_t resultsp;
187544015Smckusick 	struct sockaddr_in *raddr;
187644015Smckusick {
187744015Smckusick 	return (1);
187844015Smckusick }
187944015Smckusick 
188044015Smckusick /*
188151667Smckusick  * Free up a group list.
188251667Smckusick  */
188351667Smckusick void
188451667Smckusick free_grp(grp)
188566163Spendry 	struct grouplist *grp;
188651667Smckusick {
188766163Spendry 	char **addrp;
188851667Smckusick 
188951898Smckusick 	if (grp->gr_type == GT_HOST) {
189051712Smckusick 		if (grp->gr_ptr.gt_hostent->h_name) {
189151712Smckusick 			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
189251712Smckusick 			while (addrp && *addrp)
189351712Smckusick 				free(*addrp++);
189451712Smckusick 			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
189551712Smckusick 			free(grp->gr_ptr.gt_hostent->h_name);
189651712Smckusick 		}
189751667Smckusick 		free((caddr_t)grp->gr_ptr.gt_hostent);
189851898Smckusick 	} else if (grp->gr_type == GT_NET) {
189951898Smckusick 		if (grp->gr_ptr.gt_net.nt_name)
190051898Smckusick 			free(grp->gr_ptr.gt_net.nt_name);
190151667Smckusick 	}
190251667Smckusick #ifdef ISO
190351898Smckusick 	else if (grp->gr_type == GT_ISO)
190451667Smckusick 		free((caddr_t)grp->gr_ptr.gt_isoaddr);
190551667Smckusick #endif
190651667Smckusick 	free((caddr_t)grp);
190751667Smckusick }
190851667Smckusick 
190951711Smckusick #ifdef DEBUG
191051711Smckusick void
191151711Smckusick SYSLOG(int pri, const char *fmt, ...)
191251711Smckusick {
191351711Smckusick 	va_list ap;
191451711Smckusick 
191551711Smckusick 	va_start(ap, fmt);
191651711Smckusick 	vfprintf(stderr, fmt, ap);
191751711Smckusick 	va_end(ap);
191851711Smckusick }
191951711Smckusick #endif /* DEBUG */
192051898Smckusick 
192151898Smckusick /*
192251898Smckusick  * Check options for consistency.
192351898Smckusick  */
192466163Spendry int
192551898Smckusick check_options(dp)
192651898Smckusick 	struct dirlist *dp;
192751898Smckusick {
192851898Smckusick 
192966163Spendry 	if (dp == (struct dirlist *)NULL)
193051898Smckusick 	    return (1);
193151898Smckusick 	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
193251898Smckusick 	    (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
193351898Smckusick 	    (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
193451898Smckusick 	    syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
193551898Smckusick 	    return (1);
193651898Smckusick 	}
193751898Smckusick 	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
193851898Smckusick 	    syslog(LOG_ERR, "-mask requires -net");
193951898Smckusick 	    return (1);
194051898Smckusick 	}
194151898Smckusick 	if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
194251898Smckusick 	    syslog(LOG_ERR, "-net and -iso mutually exclusive");
194351898Smckusick 	    return (1);
194451898Smckusick 	}
194551898Smckusick 	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
194651898Smckusick 	    syslog(LOG_ERR, "-alldir has multiple directories");
194751898Smckusick 	    return (1);
194851898Smckusick 	}
194951898Smckusick 	return (0);
195051898Smckusick }
195165940Sbostic 
195265940Sbostic /*
195365940Sbostic  * Check an absolute directory path for any symbolic links. Return true
195465940Sbostic  * if no symbolic links are found.
195565940Sbostic  */
195665940Sbostic int
195765940Sbostic check_dirpath(dirp)
195866163Spendry 	char *dirp;
195965940Sbostic {
196066163Spendry 	char *cp;
196165940Sbostic 	int ret = 1;
196265940Sbostic 	struct stat sb;
196365940Sbostic 
196465940Sbostic 	cp = dirp + 1;
196565940Sbostic 	while (*cp && ret) {
196665940Sbostic 		if (*cp == '/') {
196765940Sbostic 			*cp = '\0';
1968*67383Smkm 			if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
196965940Sbostic 				ret = 0;
197065940Sbostic 			*cp = '/';
197165940Sbostic 		}
197265940Sbostic 		cp++;
197365940Sbostic 	}
1974*67383Smkm 	if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
197565940Sbostic 		ret = 0;
197665940Sbostic 	return (ret);
197765940Sbostic }
1978