xref: /csrg-svn/sbin/mountd/mountd.c (revision 68095)
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*68095Shibler static char sccsid[] = "@(#)mountd.c	8.11 (Berkeley) 12/27/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 };
17967701Smckusick int resvport_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':
21667701Smckusick 			resvport_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 stat stb;
28151898Smckusick 	struct statfs fsb;
28238460Smckusick 	struct hostent *hp;
28339681Smckusick 	u_long saddr;
28467701Smckusick 	u_short sport;
28551667Smckusick 	char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN];
28651898Smckusick 	int bad = ENOENT, omask, defset;
28738460Smckusick 
28839681Smckusick 	saddr = transp->xp_raddr.sin_addr.s_addr;
28967701Smckusick 	sport = ntohs(transp->xp_raddr.sin_port);
29066163Spendry 	hp = (struct hostent *)NULL;
29138460Smckusick 	switch (rqstp->rq_proc) {
29239681Smckusick 	case NULLPROC:
29366163Spendry 		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
29439681Smckusick 			syslog(LOG_ERR, "Can't send reply");
29539681Smckusick 		return;
29638460Smckusick 	case RPCMNT_MOUNT:
29767701Smckusick 		if (sport >= IPPORT_RESERVED && resvport_only) {
29839681Smckusick 			svcerr_weakauth(transp);
29939681Smckusick 			return;
30039681Smckusick 		}
30151667Smckusick 		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
30238460Smckusick 			svcerr_decode(transp);
30338460Smckusick 			return;
30438460Smckusick 		}
30538460Smckusick 
30651667Smckusick 		/*
30767701Smckusick 		 * Get the real pathname and make sure it is a file or
30867701Smckusick 		 * directory that exists.
30951667Smckusick 		 */
31051898Smckusick 		if (realpath(rpcpath, dirpath) == 0 ||
31151898Smckusick 		    stat(dirpath, &stb) < 0 ||
31267383Smkm 		    (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) ||
31351898Smckusick 		    statfs(dirpath, &fsb) < 0) {
31451667Smckusick 			chdir("/");	/* Just in case realpath doesn't */
31551667Smckusick 			if (debug)
31651898Smckusick 				fprintf(stderr, "stat failed on %s\n", dirpath);
31738460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
31838460Smckusick 				syslog(LOG_ERR, "Can't send reply");
31938460Smckusick 			return;
32038460Smckusick 		}
32138460Smckusick 
32238460Smckusick 		/* Check in the exports list */
32338460Smckusick 		omask = sigblock(sigmask(SIGHUP));
32451898Smckusick 		ep = ex_search(&fsb.f_fsid);
32551898Smckusick 		defset = 0;
32651898Smckusick 		if (ep && (chk_host(ep->ex_defdir, saddr, &defset) ||
32751898Smckusick 		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
32851898Smckusick 		     chk_host(dp, saddr, &defset)) ||
32951898Smckusick 		     (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
33051898Smckusick 		      scan_tree(ep->ex_dirl, saddr) == 0))) {
33151667Smckusick 			/* Get the file handle */
33251667Smckusick 			bzero((caddr_t)&nfh, sizeof(nfh));
33351667Smckusick 			if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
33451667Smckusick 				bad = errno;
33551898Smckusick 				syslog(LOG_ERR, "Can't get fh for %s", dirpath);
33651667Smckusick 				if (!svc_sendreply(transp, xdr_long,
33751667Smckusick 				    (caddr_t)&bad))
33851667Smckusick 					syslog(LOG_ERR, "Can't send reply");
33951667Smckusick 				sigsetmask(omask);
34051667Smckusick 				return;
34151667Smckusick 			}
34251667Smckusick 			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
34338460Smckusick 				syslog(LOG_ERR, "Can't send reply");
34451667Smckusick 			if (hp == NULL)
34551667Smckusick 				hp = gethostbyaddr((caddr_t)&saddr,
34651667Smckusick 				    sizeof(saddr), AF_INET);
34751667Smckusick 			if (hp)
34851667Smckusick 				add_mlist(hp->h_name, dirpath);
34951667Smckusick 			else
35051667Smckusick 				add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
35151667Smckusick 					dirpath);
35251667Smckusick 			if (debug)
35351667Smckusick 				fprintf(stderr,"Mount successfull.\n");
35451898Smckusick 		} else {
35551898Smckusick 			bad = EACCES;
35651898Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
35751898Smckusick 				syslog(LOG_ERR, "Can't send reply");
35838460Smckusick 		}
35951667Smckusick 		sigsetmask(omask);
36038460Smckusick 		return;
36138460Smckusick 	case RPCMNT_DUMP:
36266163Spendry 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL))
36338460Smckusick 			syslog(LOG_ERR, "Can't send reply");
36438460Smckusick 		return;
36538460Smckusick 	case RPCMNT_UMOUNT:
36667701Smckusick 		if (sport >= IPPORT_RESERVED && resvport_only) {
36739681Smckusick 			svcerr_weakauth(transp);
36839681Smckusick 			return;
36939681Smckusick 		}
37038460Smckusick 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
37138460Smckusick 			svcerr_decode(transp);
37238460Smckusick 			return;
37338460Smckusick 		}
37466163Spendry 		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
37538460Smckusick 			syslog(LOG_ERR, "Can't send reply");
37644015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
37744015Smckusick 		if (hp)
37844015Smckusick 			del_mlist(hp->h_name, dirpath);
37951667Smckusick 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
38038460Smckusick 		return;
38138460Smckusick 	case RPCMNT_UMNTALL:
38267701Smckusick 		if (sport >= IPPORT_RESERVED && resvport_only) {
38339681Smckusick 			svcerr_weakauth(transp);
38439681Smckusick 			return;
38539681Smckusick 		}
38666163Spendry 		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
38738460Smckusick 			syslog(LOG_ERR, "Can't send reply");
38844015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
38944015Smckusick 		if (hp)
39066163Spendry 			del_mlist(hp->h_name, (char *)NULL);
39166163Spendry 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL);
39238460Smckusick 		return;
39338460Smckusick 	case RPCMNT_EXPORT:
39466163Spendry 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL))
39538460Smckusick 			syslog(LOG_ERR, "Can't send reply");
39638460Smckusick 		return;
39738460Smckusick 	default:
39838460Smckusick 		svcerr_noproc(transp);
39938460Smckusick 		return;
40038460Smckusick 	}
40138460Smckusick }
40238460Smckusick 
40338460Smckusick /*
40438460Smckusick  * Xdr conversion for a dirpath string
40538460Smckusick  */
40666163Spendry int
40738460Smckusick xdr_dir(xdrsp, dirp)
40838460Smckusick 	XDR *xdrsp;
40938460Smckusick 	char *dirp;
41038460Smckusick {
41138460Smckusick 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
41238460Smckusick }
41338460Smckusick 
41438460Smckusick /*
41538460Smckusick  * Xdr routine to generate fhstatus
41638460Smckusick  */
41766163Spendry int
41838460Smckusick xdr_fhs(xdrsp, nfh)
41938460Smckusick 	XDR *xdrsp;
42038460Smckusick 	nfsv2fh_t *nfh;
42138460Smckusick {
42238460Smckusick 	int ok = 0;
42338460Smckusick 
42438460Smckusick 	if (!xdr_long(xdrsp, &ok))
42538460Smckusick 		return (0);
42638460Smckusick 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
42738460Smckusick }
42838460Smckusick 
42966163Spendry int
43038460Smckusick xdr_mlist(xdrsp, cp)
43138460Smckusick 	XDR *xdrsp;
43238460Smckusick 	caddr_t cp;
43338460Smckusick {
43466163Spendry 	struct mountlist *mlp;
43538460Smckusick 	int true = 1;
43638460Smckusick 	int false = 0;
43738460Smckusick 	char *strp;
43838460Smckusick 
43944015Smckusick 	mlp = mlhead;
44044015Smckusick 	while (mlp) {
44144015Smckusick 		if (!xdr_bool(xdrsp, &true))
44244015Smckusick 			return (0);
44344015Smckusick 		strp = &mlp->ml_host[0];
44444015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
44544015Smckusick 			return (0);
44644015Smckusick 		strp = &mlp->ml_dirp[0];
44744015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
44844015Smckusick 			return (0);
44944015Smckusick 		mlp = mlp->ml_next;
45038460Smckusick 	}
45138460Smckusick 	if (!xdr_bool(xdrsp, &false))
45238460Smckusick 		return (0);
45338460Smckusick 	return (1);
45438460Smckusick }
45538460Smckusick 
45638460Smckusick /*
45738460Smckusick  * Xdr conversion for export list
45838460Smckusick  */
45966163Spendry int
46038460Smckusick xdr_explist(xdrsp, cp)
46138460Smckusick 	XDR *xdrsp;
46238460Smckusick 	caddr_t cp;
46338460Smckusick {
46466163Spendry 	struct exportlist *ep;
46538460Smckusick 	int false = 0;
46664903Smckusick 	int omask, putdef;
46738460Smckusick 
46838460Smckusick 	omask = sigblock(sigmask(SIGHUP));
46951898Smckusick 	ep = exphead;
47051898Smckusick 	while (ep) {
47164903Smckusick 		putdef = 0;
47264903Smckusick 		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef))
47338460Smckusick 			goto errout;
47464903Smckusick 		if (ep->ex_defdir && putdef == 0 &&
47566163Spendry 			put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL,
47664903Smckusick 			&putdef))
47764903Smckusick 			goto errout;
47838460Smckusick 		ep = ep->ex_next;
47938460Smckusick 	}
48038460Smckusick 	sigsetmask(omask);
48138460Smckusick 	if (!xdr_bool(xdrsp, &false))
48238460Smckusick 		return (0);
48338460Smckusick 	return (1);
48438460Smckusick errout:
48538460Smckusick 	sigsetmask(omask);
48638460Smckusick 	return (0);
48738460Smckusick }
48838460Smckusick 
48951898Smckusick /*
49051898Smckusick  * Called from xdr_explist() to traverse the tree and export the
49151898Smckusick  * directory paths.
49251898Smckusick  */
49366163Spendry int
49464903Smckusick put_exlist(dp, xdrsp, adp, putdefp)
49566163Spendry 	struct dirlist *dp;
49651898Smckusick 	XDR *xdrsp;
49751898Smckusick 	struct dirlist *adp;
49864903Smckusick 	int *putdefp;
49951898Smckusick {
50066163Spendry 	struct grouplist *grp;
50166163Spendry 	struct hostlist *hp;
50251898Smckusick 	int true = 1;
50351898Smckusick 	int false = 0;
50451898Smckusick 	int gotalldir = 0;
50551898Smckusick 	char *strp;
50651898Smckusick 
50751898Smckusick 	if (dp) {
50864903Smckusick 		if (put_exlist(dp->dp_left, xdrsp, adp, putdefp))
50951898Smckusick 			return (1);
51051898Smckusick 		if (!xdr_bool(xdrsp, &true))
51151898Smckusick 			return (1);
51251898Smckusick 		strp = dp->dp_dirp;
51351898Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
51451898Smckusick 			return (1);
51564903Smckusick 		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
51651898Smckusick 			gotalldir = 1;
51764903Smckusick 			*putdefp = 1;
51864903Smckusick 		}
51951898Smckusick 		if ((dp->dp_flag & DP_DEFSET) == 0 &&
52051898Smckusick 		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
52151898Smckusick 			hp = dp->dp_hosts;
52251898Smckusick 			while (hp) {
52351898Smckusick 				grp = hp->ht_grp;
52451898Smckusick 				if (grp->gr_type == GT_HOST) {
52551898Smckusick 					if (!xdr_bool(xdrsp, &true))
52651898Smckusick 						return (1);
52751898Smckusick 					strp = grp->gr_ptr.gt_hostent->h_name;
52851898Smckusick 					if (!xdr_string(xdrsp, &strp,
52951898Smckusick 					    RPCMNT_NAMELEN))
53051898Smckusick 						return (1);
53151898Smckusick 				} else if (grp->gr_type == GT_NET) {
53251898Smckusick 					if (!xdr_bool(xdrsp, &true))
53351898Smckusick 						return (1);
53451898Smckusick 					strp = grp->gr_ptr.gt_net.nt_name;
53551898Smckusick 					if (!xdr_string(xdrsp, &strp,
53651898Smckusick 					    RPCMNT_NAMELEN))
53751898Smckusick 						return (1);
53851898Smckusick 				}
53951898Smckusick 				hp = hp->ht_next;
54066163Spendry 				if (gotalldir && hp == (struct hostlist *)NULL) {
54151898Smckusick 					hp = adp->dp_hosts;
54251898Smckusick 					gotalldir = 0;
54351898Smckusick 				}
54451898Smckusick 			}
54551898Smckusick 		}
54651898Smckusick 		if (!xdr_bool(xdrsp, &false))
54751898Smckusick 			return (1);
54864903Smckusick 		if (put_exlist(dp->dp_right, xdrsp, adp, putdefp))
54951898Smckusick 			return (1);
55051898Smckusick 	}
55151898Smckusick 	return (0);
55251898Smckusick }
55351898Smckusick 
55438460Smckusick #define LINESIZ	10240
55538460Smckusick char line[LINESIZ];
55651898Smckusick FILE *exp_file;
55738460Smckusick 
55838460Smckusick /*
55938460Smckusick  * Get the export list
56038460Smckusick  */
56146709Sbostic void
56238460Smckusick get_exportlist()
56338460Smckusick {
56466163Spendry 	struct exportlist *ep, *ep2;
56566163Spendry 	struct grouplist *grp, *tgrp;
56651898Smckusick 	struct exportlist **epp;
56751898Smckusick 	struct dirlist *dirhead;
56852109Smckusick 	struct statfs fsb, *fsp;
56951898Smckusick 	struct hostent *hpe;
57051898Smckusick 	struct ucred anon;
57153150Smckusick 	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
57253150Smckusick 	int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
57338460Smckusick 
57438460Smckusick 	/*
57538460Smckusick 	 * First, get rid of the old list
57638460Smckusick 	 */
57751898Smckusick 	ep = exphead;
57851898Smckusick 	while (ep) {
57938460Smckusick 		ep2 = ep;
58038460Smckusick 		ep = ep->ex_next;
58144015Smckusick 		free_exp(ep2);
58238460Smckusick 	}
58366163Spendry 	exphead = (struct exportlist *)NULL;
58438460Smckusick 
58551898Smckusick 	grp = grphead;
58651898Smckusick 	while (grp) {
58751898Smckusick 		tgrp = grp;
58851898Smckusick 		grp = grp->gr_next;
58951898Smckusick 		free_grp(tgrp);
59051667Smckusick 	}
59166163Spendry 	grphead = (struct grouplist *)NULL;
59251667Smckusick 
59338460Smckusick 	/*
59452109Smckusick 	 * And delete exports that are in the kernel for all local
59552109Smckusick 	 * file systems.
59652109Smckusick 	 * XXX: Should know how to handle all local exportable file systems
59752109Smckusick 	 *      instead of just MOUNT_UFS.
59852109Smckusick 	 */
59953214Smckusick 	num = getmntinfo(&fsp, MNT_NOWAIT);
60052109Smckusick 	for (i = 0; i < num; i++) {
60165713Shibler 		union {
60265713Shibler 			struct ufs_args ua;
60365713Shibler 			struct iso_args ia;
60465713Shibler 			struct mfs_args ma;
60565713Shibler 		} targs;
60665713Shibler 
60765713Shibler 		switch (fsp->f_type) {
60865863Sbostic 		case MOUNT_MFS:
60965713Shibler 		case MOUNT_UFS:
61065863Sbostic 		case MOUNT_CD9660:
61165863Sbostic 			targs.ua.fspec = NULL;
61265713Shibler 			targs.ua.export.ex_flags = MNT_DELEXPORT;
61352109Smckusick 			if (mount(fsp->f_type, fsp->f_mntonname,
61465713Shibler 				  fsp->f_flags | MNT_UPDATE,
61565713Shibler 				  (caddr_t)&targs) < 0)
61665713Shibler 				syslog(LOG_ERR, "Can't delete exports for %s",
61752109Smckusick 				       fsp->f_mntonname);
61852109Smckusick 		}
61952109Smckusick 		fsp++;
62052109Smckusick 	}
62152109Smckusick 
62252109Smckusick 	/*
62338460Smckusick 	 * Read in the exports file and build the list, calling
62451667Smckusick 	 * mount() as we go along to push the export rules into the kernel.
62538460Smckusick 	 */
62651898Smckusick 	if ((exp_file = fopen(exname, "r")) == NULL) {
62738460Smckusick 		syslog(LOG_ERR, "Can't open %s", exname);
62838460Smckusick 		exit(2);
62938460Smckusick 	}
63066163Spendry 	dirhead = (struct dirlist *)NULL;
63151898Smckusick 	while (get_line()) {
63251667Smckusick 		if (debug)
63351667Smckusick 			fprintf(stderr,"Got line %s\n",line);
63438460Smckusick 		cp = line;
63538460Smckusick 		nextfield(&cp, &endcp);
63651667Smckusick 		if (*cp == '#')
63751667Smckusick 			goto nextline;
63851898Smckusick 
63951898Smckusick 		/*
64051898Smckusick 		 * Set defaults.
64151898Smckusick 		 */
64251898Smckusick 		has_host = FALSE;
64351898Smckusick 		anon = def_anon;
64451667Smckusick 		exflags = MNT_EXPORTED;
64551898Smckusick 		got_nondir = 0;
64651898Smckusick 		opt_flags = 0;
64766163Spendry 		ep = (struct exportlist *)NULL;
64844015Smckusick 
64944015Smckusick 		/*
65044015Smckusick 		 * Create new exports list entry
65144015Smckusick 		 */
65238460Smckusick 		len = endcp-cp;
65353150Smckusick 		tgrp = grp = get_grp();
65451898Smckusick 		while (len > 0) {
65551898Smckusick 			if (len > RPCMNT_NAMELEN) {
65653150Smckusick 			    getexp_err(ep, tgrp);
65751898Smckusick 			    goto nextline;
65851667Smckusick 			}
65945271Smckusick 			if (*cp == '-') {
66066163Spendry 			    if (ep == (struct exportlist *)NULL) {
66153150Smckusick 				getexp_err(ep, tgrp);
66251898Smckusick 				goto nextline;
66351898Smckusick 			    }
66451898Smckusick 			    if (debug)
66551898Smckusick 				fprintf(stderr, "doing opt %s\n", cp);
66651898Smckusick 			    got_nondir = 1;
66751898Smckusick 			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
66851898Smckusick 				&exflags, &anon)) {
66953150Smckusick 				getexp_err(ep, tgrp);
67051898Smckusick 				goto nextline;
67151898Smckusick 			    }
67251898Smckusick 			} else if (*cp == '/') {
67351898Smckusick 			    savedc = *endcp;
67451898Smckusick 			    *endcp = '\0';
67565940Sbostic 			    if (check_dirpath(cp) &&
67651898Smckusick 				statfs(cp, &fsb) >= 0) {
67751898Smckusick 				if (got_nondir) {
67851898Smckusick 				    syslog(LOG_ERR, "Dirs must be first");
67953150Smckusick 				    getexp_err(ep, tgrp);
68051898Smckusick 				    goto nextline;
68151898Smckusick 				}
68251898Smckusick 				if (ep) {
68351898Smckusick 				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
68451898Smckusick 					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
68553150Smckusick 					getexp_err(ep, tgrp);
68651898Smckusick 					goto nextline;
68751898Smckusick 				    }
68851667Smckusick 				} else {
68951898Smckusick 				    /*
69051898Smckusick 				     * See if this directory is already
69151898Smckusick 				     * in the list.
69251898Smckusick 				     */
69351898Smckusick 				    ep = ex_search(&fsb.f_fsid);
69466163Spendry 				    if (ep == (struct exportlist *)NULL) {
69551898Smckusick 					ep = get_exp();
69651898Smckusick 					ep->ex_fs = fsb.f_fsid;
69751898Smckusick 					ep->ex_fsdir = (char *)
69851898Smckusick 					    malloc(strlen(fsb.f_mntonname) + 1);
69951898Smckusick 					if (ep->ex_fsdir)
70051898Smckusick 					    strcpy(ep->ex_fsdir,
70151898Smckusick 						fsb.f_mntonname);
70251898Smckusick 					else
70351898Smckusick 					    out_of_mem();
70451898Smckusick 					if (debug)
70551898Smckusick 					  fprintf(stderr,
70651898Smckusick 					      "Making new ep fs=0x%x,0x%x\n",
70751898Smckusick 					      fsb.f_fsid.val[0],
70851898Smckusick 					      fsb.f_fsid.val[1]);
70951898Smckusick 				    } else if (debug)
71051898Smckusick 					fprintf(stderr,
71151898Smckusick 					    "Found ep fs=0x%x,0x%x\n",
71251898Smckusick 					    fsb.f_fsid.val[0],
71351898Smckusick 					    fsb.f_fsid.val[1]);
71438460Smckusick 				}
71551898Smckusick 
71651898Smckusick 				/*
71751898Smckusick 				 * Add dirpath to export mount point.
71851898Smckusick 				 */
71951898Smckusick 				dirp = add_expdir(&dirhead, cp, len);
72051898Smckusick 				dirplen = len;
72151898Smckusick 			    } else {
72253150Smckusick 				getexp_err(ep, tgrp);
72351898Smckusick 				goto nextline;
72451898Smckusick 			    }
72551898Smckusick 			    *endcp = savedc;
72651898Smckusick 			} else {
72751898Smckusick 			    savedc = *endcp;
72851898Smckusick 			    *endcp = '\0';
72951898Smckusick 			    got_nondir = 1;
73066163Spendry 			    if (ep == (struct exportlist *)NULL) {
73153150Smckusick 				getexp_err(ep, tgrp);
73251898Smckusick 				goto nextline;
73351898Smckusick 			    }
73453150Smckusick 
73553150Smckusick 			    /*
73653150Smckusick 			     * Get the host or netgroup.
73753150Smckusick 			     */
73853150Smckusick 			    setnetgrent(cp);
73953150Smckusick 			    netgrp = getnetgrent(&hst, &usr, &dom);
74053150Smckusick 			    do {
74153150Smckusick 				if (has_host) {
74253150Smckusick 				    grp->gr_next = get_grp();
74353150Smckusick 				    grp = grp->gr_next;
74453150Smckusick 				}
74553150Smckusick 				if (netgrp) {
74653150Smckusick 				    if (get_host(hst, grp)) {
74753150Smckusick 					syslog(LOG_ERR, "Bad netgroup %s", cp);
74853150Smckusick 					getexp_err(ep, tgrp);
749*68095Shibler 					endnetgrent();
75053150Smckusick 					goto nextline;
75153150Smckusick 				    }
75253150Smckusick 				} else if (get_host(cp, grp)) {
75353150Smckusick 				    getexp_err(ep, tgrp);
75453150Smckusick 				    goto nextline;
75553150Smckusick 				}
75653150Smckusick 				has_host = TRUE;
75753150Smckusick 			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
75853150Smckusick 			    endnetgrent();
75951898Smckusick 			    *endcp = savedc;
76038460Smckusick 			}
76138460Smckusick 			cp = endcp;
76238460Smckusick 			nextfield(&cp, &endcp);
76345271Smckusick 			len = endcp - cp;
76438460Smckusick 		}
76551898Smckusick 		if (check_options(dirhead)) {
76653150Smckusick 			getexp_err(ep, tgrp);
76751898Smckusick 			goto nextline;
76851898Smckusick 		}
76951898Smckusick 		if (!has_host) {
77051898Smckusick 			grp->gr_type = GT_HOST;
77151667Smckusick 			if (debug)
77251667Smckusick 				fprintf(stderr,"Adding a default entry\n");
77351667Smckusick 			/* add a default group and make the grp list NULL */
77451667Smckusick 			hpe = (struct hostent *)malloc(sizeof(struct hostent));
77566163Spendry 			if (hpe == (struct hostent *)NULL)
77651898Smckusick 				out_of_mem();
77751898Smckusick 			hpe->h_name = "Default";
77851667Smckusick 			hpe->h_addrtype = AF_INET;
77951667Smckusick 			hpe->h_length = sizeof (u_long);
78066163Spendry 			hpe->h_addr_list = (char **)NULL;
78151898Smckusick 			grp->gr_ptr.gt_hostent = hpe;
78253150Smckusick 
78353150Smckusick 		/*
78453150Smckusick 		 * Don't allow a network export coincide with a list of
78553150Smckusick 		 * host(s) on the same line.
78653150Smckusick 		 */
78753150Smckusick 		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
78853150Smckusick 			getexp_err(ep, tgrp);
78953150Smckusick 			goto nextline;
79051667Smckusick 		}
79153150Smckusick 
79253150Smckusick 		/*
79353150Smckusick 		 * Loop through hosts, pushing the exports into the kernel.
79453150Smckusick 		 * After loop, tgrp points to the start of the list and
79553150Smckusick 		 * grp points to the last entry in the list.
79653150Smckusick 		 */
79753150Smckusick 		grp = tgrp;
79853150Smckusick 		do {
79953150Smckusick 		    if (do_mount(ep, grp, exflags, &anon, dirp,
80051898Smckusick 			dirplen, &fsb)) {
80153150Smckusick 			getexp_err(ep, tgrp);
80251898Smckusick 			goto nextline;
80353150Smckusick 		    }
80453150Smckusick 		} while (grp->gr_next && (grp = grp->gr_next));
80551898Smckusick 
80651898Smckusick 		/*
80751898Smckusick 		 * Success. Update the data structures.
80851898Smckusick 		 */
80951898Smckusick 		if (has_host) {
81053150Smckusick 			hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS));
81151898Smckusick 			grp->gr_next = grphead;
81253150Smckusick 			grphead = tgrp;
81351898Smckusick 		} else {
81466163Spendry 			hang_dirp(dirhead, (struct grouplist *)NULL, ep,
81553150Smckusick 			(opt_flags & OP_ALLDIRS));
81651898Smckusick 			free_grp(grp);
81751898Smckusick 		}
81866163Spendry 		dirhead = (struct dirlist *)NULL;
81951898Smckusick 		if ((ep->ex_flag & EX_LINKED) == 0) {
82051898Smckusick 			ep2 = exphead;
82151898Smckusick 			epp = &exphead;
82251898Smckusick 
82351898Smckusick 			/*
82451898Smckusick 			 * Insert in the list in alphabetical order.
82551898Smckusick 			 */
82651898Smckusick 			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
82751898Smckusick 				epp = &ep2->ex_next;
82851898Smckusick 				ep2 = ep2->ex_next;
82951898Smckusick 			}
83051898Smckusick 			if (ep2)
83151898Smckusick 				ep->ex_next = ep2;
83251898Smckusick 			*epp = ep;
83351898Smckusick 			ep->ex_flag |= EX_LINKED;
83451898Smckusick 		}
83551898Smckusick nextline:
83651898Smckusick 		if (dirhead) {
83751898Smckusick 			free_dir(dirhead);
83866163Spendry 			dirhead = (struct dirlist *)NULL;
83951898Smckusick 		}
84051898Smckusick 	}
84151898Smckusick 	fclose(exp_file);
84251898Smckusick }
84351898Smckusick 
84451898Smckusick /*
84551898Smckusick  * Allocate an export list element
84651898Smckusick  */
84751898Smckusick struct exportlist *
84851898Smckusick get_exp()
84951898Smckusick {
85066163Spendry 	struct exportlist *ep;
85151898Smckusick 
85251898Smckusick 	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
85366163Spendry 	if (ep == (struct exportlist *)NULL)
85451898Smckusick 		out_of_mem();
85551898Smckusick 	bzero((caddr_t)ep, sizeof (struct exportlist));
85651898Smckusick 	return (ep);
85751898Smckusick }
85851898Smckusick 
85951898Smckusick /*
86051898Smckusick  * Allocate a group list element
86151898Smckusick  */
86251898Smckusick struct grouplist *
86351898Smckusick get_grp()
86451898Smckusick {
86566163Spendry 	struct grouplist *gp;
86651898Smckusick 
86751898Smckusick 	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
86866163Spendry 	if (gp == (struct grouplist *)NULL)
86951898Smckusick 		out_of_mem();
87051898Smckusick 	bzero((caddr_t)gp, sizeof (struct grouplist));
87151898Smckusick 	return (gp);
87251898Smckusick }
87351898Smckusick 
87451898Smckusick /*
87551898Smckusick  * Clean up upon an error in get_exportlist().
87651898Smckusick  */
87751898Smckusick void
87851898Smckusick getexp_err(ep, grp)
87951898Smckusick 	struct exportlist *ep;
88051898Smckusick 	struct grouplist *grp;
88151898Smckusick {
88253150Smckusick 	struct grouplist *tgrp;
88351898Smckusick 
88451898Smckusick 	syslog(LOG_ERR, "Bad exports list line %s", line);
88559017Smckusick 	if (ep && (ep->ex_flag & EX_LINKED) == 0)
88651898Smckusick 		free_exp(ep);
88753150Smckusick 	while (grp) {
88853150Smckusick 		tgrp = grp;
88953150Smckusick 		grp = grp->gr_next;
89053150Smckusick 		free_grp(tgrp);
89153150Smckusick 	}
89251898Smckusick }
89351898Smckusick 
89451898Smckusick /*
89551898Smckusick  * Search the export list for a matching fs.
89651898Smckusick  */
89751898Smckusick struct exportlist *
89851898Smckusick ex_search(fsid)
89952109Smckusick 	fsid_t *fsid;
90051898Smckusick {
90166163Spendry 	struct exportlist *ep;
90251898Smckusick 
90351898Smckusick 	ep = exphead;
90451898Smckusick 	while (ep) {
90551898Smckusick 		if (ep->ex_fs.val[0] == fsid->val[0] &&
90651898Smckusick 		    ep->ex_fs.val[1] == fsid->val[1])
90751898Smckusick 			return (ep);
90851898Smckusick 		ep = ep->ex_next;
90951898Smckusick 	}
91051898Smckusick 	return (ep);
91151898Smckusick }
91251898Smckusick 
91351898Smckusick /*
91451898Smckusick  * Add a directory path to the list.
91551898Smckusick  */
91651898Smckusick char *
91751898Smckusick add_expdir(dpp, cp, len)
91851898Smckusick 	struct dirlist **dpp;
91951898Smckusick 	char *cp;
92051898Smckusick 	int len;
92151898Smckusick {
92266163Spendry 	struct dirlist *dp;
92351898Smckusick 
92451898Smckusick 	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
92551898Smckusick 	dp->dp_left = *dpp;
92666163Spendry 	dp->dp_right = (struct dirlist *)NULL;
92751898Smckusick 	dp->dp_flag = 0;
92866163Spendry 	dp->dp_hosts = (struct hostlist *)NULL;
92951898Smckusick 	strcpy(dp->dp_dirp, cp);
93051898Smckusick 	*dpp = dp;
93151898Smckusick 	return (dp->dp_dirp);
93251898Smckusick }
93351898Smckusick 
93451898Smckusick /*
93551898Smckusick  * Hang the dir list element off the dirpath binary tree as required
93651898Smckusick  * and update the entry for host.
93751898Smckusick  */
93851898Smckusick void
93951898Smckusick hang_dirp(dp, grp, ep, alldirs)
94066163Spendry 	struct dirlist *dp;
94151898Smckusick 	struct grouplist *grp;
94251898Smckusick 	struct exportlist *ep;
94351898Smckusick 	int alldirs;
94451898Smckusick {
94566163Spendry 	struct hostlist *hp;
94651898Smckusick 	struct dirlist *dp2;
94751898Smckusick 
94851898Smckusick 	if (alldirs) {
94951898Smckusick 		if (ep->ex_defdir)
95051898Smckusick 			free((caddr_t)dp);
95151898Smckusick 		else
95251898Smckusick 			ep->ex_defdir = dp;
95366163Spendry 		if (grp == (struct grouplist *)NULL)
95455292Smckusick 			ep->ex_defdir->dp_flag |= DP_DEFSET;
95555292Smckusick 		else while (grp) {
95651898Smckusick 			hp = get_ht();
95751898Smckusick 			hp->ht_grp = grp;
95851898Smckusick 			hp->ht_next = ep->ex_defdir->dp_hosts;
95951898Smckusick 			ep->ex_defdir->dp_hosts = hp;
96055292Smckusick 			grp = grp->gr_next;
96155292Smckusick 		}
96251898Smckusick 	} else {
96353150Smckusick 
96453150Smckusick 		/*
96553150Smckusick 		 * Loop throught the directories adding them to the tree.
96653150Smckusick 		 */
96751898Smckusick 		while (dp) {
96851898Smckusick 			dp2 = dp->dp_left;
96953150Smckusick 			add_dlist(&ep->ex_dirl, dp, grp);
97051898Smckusick 			dp = dp2;
97151898Smckusick 		}
97251898Smckusick 	}
97351898Smckusick }
97451898Smckusick 
97551898Smckusick /*
97651898Smckusick  * Traverse the binary tree either updating a node that is already there
97751898Smckusick  * for the new directory or adding the new node.
97851898Smckusick  */
97951898Smckusick void
98053150Smckusick add_dlist(dpp, newdp, grp)
98151898Smckusick 	struct dirlist **dpp;
98251898Smckusick 	struct dirlist *newdp;
98366163Spendry 	struct grouplist *grp;
98451898Smckusick {
98566163Spendry 	struct dirlist *dp;
98666163Spendry 	struct hostlist *hp;
98751898Smckusick 	int cmp;
98851898Smckusick 
98951898Smckusick 	dp = *dpp;
99051898Smckusick 	if (dp) {
99151898Smckusick 		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
99251898Smckusick 		if (cmp > 0) {
99353150Smckusick 			add_dlist(&dp->dp_left, newdp, grp);
99451898Smckusick 			return;
99551898Smckusick 		} else if (cmp < 0) {
99653150Smckusick 			add_dlist(&dp->dp_right, newdp, grp);
99751898Smckusick 			return;
99851898Smckusick 		} else
99951898Smckusick 			free((caddr_t)newdp);
100051898Smckusick 	} else {
100151898Smckusick 		dp = newdp;
100266163Spendry 		dp->dp_left = (struct dirlist *)NULL;
100351898Smckusick 		*dpp = dp;
100451898Smckusick 	}
100553150Smckusick 	if (grp) {
100653150Smckusick 
100753150Smckusick 		/*
100853150Smckusick 		 * Hang all of the host(s) off of the directory point.
100953150Smckusick 		 */
101053150Smckusick 		do {
101153150Smckusick 			hp = get_ht();
101253150Smckusick 			hp->ht_grp = grp;
101353150Smckusick 			hp->ht_next = dp->dp_hosts;
101453150Smckusick 			dp->dp_hosts = hp;
101553150Smckusick 			grp = grp->gr_next;
101653150Smckusick 		} while (grp);
101751898Smckusick 	} else
101851898Smckusick 		dp->dp_flag |= DP_DEFSET;
101951898Smckusick }
102051898Smckusick 
102151898Smckusick /*
102251898Smckusick  * Search for a dirpath on the export point.
102351898Smckusick  */
102451898Smckusick struct dirlist *
102551898Smckusick dirp_search(dp, dirpath)
102666163Spendry 	struct dirlist *dp;
102751898Smckusick 	char *dirpath;
102851898Smckusick {
102966163Spendry 	int cmp;
103051898Smckusick 
103151898Smckusick 	if (dp) {
103251898Smckusick 		cmp = strcmp(dp->dp_dirp, dirpath);
103351898Smckusick 		if (cmp > 0)
103451898Smckusick 			return (dirp_search(dp->dp_left, dirpath));
103551898Smckusick 		else if (cmp < 0)
103651898Smckusick 			return (dirp_search(dp->dp_right, dirpath));
103751898Smckusick 		else
103851898Smckusick 			return (dp);
103951898Smckusick 	}
104051898Smckusick 	return (dp);
104151898Smckusick }
104251898Smckusick 
104351898Smckusick /*
104451898Smckusick  * Scan for a host match in a directory tree.
104551898Smckusick  */
104666163Spendry int
104751898Smckusick chk_host(dp, saddr, defsetp)
104851898Smckusick 	struct dirlist *dp;
104951898Smckusick 	u_long saddr;
105051898Smckusick 	int *defsetp;
105151898Smckusick {
105266163Spendry 	struct hostlist *hp;
105366163Spendry 	struct grouplist *grp;
105466163Spendry 	u_long **addrp;
105551898Smckusick 
105651898Smckusick 	if (dp) {
105751898Smckusick 		if (dp->dp_flag & DP_DEFSET)
105851898Smckusick 			*defsetp = 1;
105951898Smckusick 		hp = dp->dp_hosts;
106051898Smckusick 		while (hp) {
106151898Smckusick 			grp = hp->ht_grp;
106251898Smckusick 			switch (grp->gr_type) {
106351898Smckusick 			case GT_HOST:
106451898Smckusick 			    addrp = (u_long **)
106551898Smckusick 				grp->gr_ptr.gt_hostent->h_addr_list;
106651898Smckusick 			    while (*addrp) {
106751898Smckusick 				if (**addrp == saddr)
106851898Smckusick 				    return (1);
106951898Smckusick 				addrp++;
107051898Smckusick 			    }
107151898Smckusick 			    break;
107251898Smckusick 			case GT_NET:
107351898Smckusick 			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
107451898Smckusick 				grp->gr_ptr.gt_net.nt_net)
107551898Smckusick 				return (1);
107651898Smckusick 			    break;
107751898Smckusick 			};
107851898Smckusick 			hp = hp->ht_next;
107951898Smckusick 		}
108051898Smckusick 	}
108151898Smckusick 	return (0);
108251898Smckusick }
108351898Smckusick 
108451898Smckusick /*
108551898Smckusick  * Scan tree for a host that matches the address.
108651898Smckusick  */
108766163Spendry int
108851898Smckusick scan_tree(dp, saddr)
108966163Spendry 	struct dirlist *dp;
109051898Smckusick 	u_long saddr;
109151898Smckusick {
109251898Smckusick 	int defset;
109351898Smckusick 
109451898Smckusick 	if (dp) {
109551898Smckusick 		if (scan_tree(dp->dp_left, saddr))
109651898Smckusick 			return (1);
109751898Smckusick 		if (chk_host(dp, saddr, &defset))
109851898Smckusick 			return (1);
109951898Smckusick 		if (scan_tree(dp->dp_right, saddr))
110051898Smckusick 			return (1);
110151898Smckusick 	}
110251898Smckusick 	return (0);
110351898Smckusick }
110451898Smckusick 
110551898Smckusick /*
110651898Smckusick  * Traverse the dirlist tree and free it up.
110751898Smckusick  */
110851898Smckusick void
110951898Smckusick free_dir(dp)
111066163Spendry 	struct dirlist *dp;
111151898Smckusick {
111251898Smckusick 
111351898Smckusick 	if (dp) {
111451898Smckusick 		free_dir(dp->dp_left);
111551898Smckusick 		free_dir(dp->dp_right);
111651898Smckusick 		free_host(dp->dp_hosts);
111751898Smckusick 		free((caddr_t)dp);
111851898Smckusick 	}
111951898Smckusick }
112051898Smckusick 
112151898Smckusick /*
112251898Smckusick  * Parse the option string and update fields.
112351898Smckusick  * Option arguments may either be -<option>=<value> or
112451898Smckusick  * -<option> <value>
112551898Smckusick  */
112666163Spendry int
112751898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
112851898Smckusick 	char **cpp, **endcpp;
112951898Smckusick 	struct exportlist *ep;
113051898Smckusick 	struct grouplist *grp;
113151898Smckusick 	int *has_hostp;
113251898Smckusick 	int *exflagsp;
113351898Smckusick 	struct ucred *cr;
113451898Smckusick {
113566163Spendry 	char *cpoptarg, *cpoptend;
113651898Smckusick 	char *cp, *endcp, *cpopt, savedc, savedc2;
113751898Smckusick 	int allflag, usedarg;
113851898Smckusick 
113951898Smckusick 	cpopt = *cpp;
114051898Smckusick 	cpopt++;
114151898Smckusick 	cp = *endcpp;
114251898Smckusick 	savedc = *cp;
114351898Smckusick 	*cp = '\0';
114451898Smckusick 	while (cpopt && *cpopt) {
114551898Smckusick 		allflag = 1;
114651898Smckusick 		usedarg = -2;
114751898Smckusick 		if (cpoptend = index(cpopt, ',')) {
114851898Smckusick 			*cpoptend++ = '\0';
114951898Smckusick 			if (cpoptarg = index(cpopt, '='))
115051898Smckusick 				*cpoptarg++ = '\0';
115151898Smckusick 		} else {
115251898Smckusick 			if (cpoptarg = index(cpopt, '='))
115351898Smckusick 				*cpoptarg++ = '\0';
115451898Smckusick 			else {
115551898Smckusick 				*cp = savedc;
115651898Smckusick 				nextfield(&cp, &endcp);
115751898Smckusick 				**endcpp = '\0';
115851898Smckusick 				if (endcp > cp && *cp != '-') {
115951898Smckusick 					cpoptarg = cp;
116051898Smckusick 					savedc2 = *endcp;
116151898Smckusick 					*endcp = '\0';
116251898Smckusick 					usedarg = 0;
116351667Smckusick 				}
116451667Smckusick 			}
116551667Smckusick 		}
116651898Smckusick 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
116751898Smckusick 			*exflagsp |= MNT_EXRDONLY;
116851898Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
116951898Smckusick 		    !(allflag = strcmp(cpopt, "mapall")) ||
117051898Smckusick 		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
117151898Smckusick 			usedarg++;
117251898Smckusick 			parsecred(cpoptarg, cr);
117351898Smckusick 			if (allflag == 0) {
117451898Smckusick 				*exflagsp |= MNT_EXPORTANON;
117551898Smckusick 				opt_flags |= OP_MAPALL;
117651898Smckusick 			} else
117751898Smckusick 				opt_flags |= OP_MAPROOT;
117851898Smckusick 		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
117951898Smckusick 			*exflagsp |= MNT_EXKERB;
118051898Smckusick 			opt_flags |= OP_KERB;
118153150Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
118253150Smckusick 			!strcmp(cpopt, "m"))) {
118351898Smckusick 			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
118451898Smckusick 				syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
118551898Smckusick 				return (1);
118651898Smckusick 			}
118751898Smckusick 			usedarg++;
118851898Smckusick 			opt_flags |= OP_MASK;
118953150Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
119053150Smckusick 			!strcmp(cpopt, "n"))) {
119151898Smckusick 			if (grp->gr_type != GT_NULL) {
119251898Smckusick 				syslog(LOG_ERR, "Network/host conflict");
119351898Smckusick 				return (1);
119451898Smckusick 			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
119551898Smckusick 				syslog(LOG_ERR, "Bad net: %s", cpoptarg);
119651898Smckusick 				return (1);
119751898Smckusick 			}
119851898Smckusick 			grp->gr_type = GT_NET;
119951898Smckusick 			*has_hostp = 1;
120051898Smckusick 			usedarg++;
120151898Smckusick 			opt_flags |= OP_NET;
120251898Smckusick 		} else if (!strcmp(cpopt, "alldirs")) {
120351898Smckusick 			opt_flags |= OP_ALLDIRS;
120451898Smckusick #ifdef ISO
120551898Smckusick 		} else if (cpoptarg && !strcmp(cpopt, "iso")) {
120651898Smckusick 			if (get_isoaddr(cpoptarg, grp)) {
120751898Smckusick 				syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
120851898Smckusick 				return (1);
120951898Smckusick 			}
121051898Smckusick 			*has_hostp = 1;
121151898Smckusick 			usedarg++;
121251898Smckusick 			opt_flags |= OP_ISO;
121351898Smckusick #endif /* ISO */
121451898Smckusick 		} else {
121551898Smckusick 			syslog(LOG_ERR, "Bad opt %s", cpopt);
121651898Smckusick 			return (1);
121751667Smckusick 		}
121851898Smckusick 		if (usedarg >= 0) {
121951898Smckusick 			*endcp = savedc2;
122051898Smckusick 			**endcpp = savedc;
122151898Smckusick 			if (usedarg > 0) {
122251898Smckusick 				*cpp = cp;
122351898Smckusick 				*endcpp = endcp;
122451898Smckusick 			}
122551898Smckusick 			return (0);
122651898Smckusick 		}
122751898Smckusick 		cpopt = cpoptend;
122851667Smckusick 	}
122951898Smckusick 	**endcpp = savedc;
123051898Smckusick 	return (0);
123151898Smckusick }
123251898Smckusick 
123351898Smckusick /*
123451898Smckusick  * Translate a character string to the corresponding list of network
123551898Smckusick  * addresses for a hostname.
123651898Smckusick  */
123766163Spendry int
123851898Smckusick get_host(cp, grp)
123951898Smckusick 	char *cp;
124066163Spendry 	struct grouplist *grp;
124151898Smckusick {
124266163Spendry 	struct hostent *hp, *nhp;
124366163Spendry 	char **addrp, **naddrp;
124451898Smckusick 	struct hostent t_host;
124551898Smckusick 	int i;
124651898Smckusick 	u_long saddr;
124751898Smckusick 	char *aptr[2];
124851898Smckusick 
124951898Smckusick 	if (grp->gr_type != GT_NULL)
125051898Smckusick 		return (1);
125151898Smckusick 	if ((hp = gethostbyname(cp)) == NULL) {
125251898Smckusick 		if (isdigit(*cp)) {
125351898Smckusick 			saddr = inet_addr(cp);
125451898Smckusick 			if (saddr == -1) {
1255*68095Shibler 				syslog(LOG_ERR, "Inet_addr failed for %s", cp);
125651898Smckusick 				return (1);
125751898Smckusick 			}
125851898Smckusick 			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
125951898Smckusick 				AF_INET)) == NULL) {
126051898Smckusick 				hp = &t_host;
126151898Smckusick 				hp->h_name = cp;
126251898Smckusick 				hp->h_addrtype = AF_INET;
126351898Smckusick 				hp->h_length = sizeof (u_long);
126451898Smckusick 				hp->h_addr_list = aptr;
126551898Smckusick 				aptr[0] = (char *)&saddr;
126666163Spendry 				aptr[1] = (char *)NULL;
126751898Smckusick 			}
126851898Smckusick 		} else {
1269*68095Shibler 			syslog(LOG_ERR, "Gethostbyname failed for %s", cp);
127051898Smckusick 			return (1);
127151898Smckusick 		}
127251898Smckusick 	}
127351898Smckusick 	grp->gr_type = GT_HOST;
127451898Smckusick 	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
127551898Smckusick 		malloc(sizeof(struct hostent));
127666163Spendry 	if (nhp == (struct hostent *)NULL)
127751898Smckusick 		out_of_mem();
127851898Smckusick 	bcopy((caddr_t)hp, (caddr_t)nhp,
127951898Smckusick 		sizeof(struct hostent));
128051898Smckusick 	i = strlen(hp->h_name)+1;
128151898Smckusick 	nhp->h_name = (char *)malloc(i);
128266163Spendry 	if (nhp->h_name == (char *)NULL)
128351898Smckusick 		out_of_mem();
128451898Smckusick 	bcopy(hp->h_name, nhp->h_name, i);
128551898Smckusick 	addrp = hp->h_addr_list;
128651898Smckusick 	i = 1;
128751898Smckusick 	while (*addrp++)
128851898Smckusick 		i++;
128951898Smckusick 	naddrp = nhp->h_addr_list = (char **)
129051898Smckusick 		malloc(i*sizeof(char *));
129166163Spendry 	if (naddrp == (char **)NULL)
129251898Smckusick 		out_of_mem();
129351898Smckusick 	addrp = hp->h_addr_list;
129451898Smckusick 	while (*addrp) {
129551898Smckusick 		*naddrp = (char *)
129651898Smckusick 		    malloc(hp->h_length);
129766163Spendry 		if (*naddrp == (char *)NULL)
129851898Smckusick 		    out_of_mem();
129951898Smckusick 		bcopy(*addrp, *naddrp,
130051898Smckusick 			hp->h_length);
130151898Smckusick 		addrp++;
130251898Smckusick 		naddrp++;
130351898Smckusick 	}
130466163Spendry 	*naddrp = (char *)NULL;
130553150Smckusick 	if (debug)
130653150Smckusick 		fprintf(stderr, "got host %s\n", hp->h_name);
130751898Smckusick 	return (0);
130851898Smckusick }
130951898Smckusick 
131051898Smckusick /*
131151898Smckusick  * Free up an exports list component
131251898Smckusick  */
131351898Smckusick void
131451898Smckusick free_exp(ep)
131566163Spendry 	struct exportlist *ep;
131651898Smckusick {
131751898Smckusick 
131851898Smckusick 	if (ep->ex_defdir) {
131951898Smckusick 		free_host(ep->ex_defdir->dp_hosts);
132051898Smckusick 		free((caddr_t)ep->ex_defdir);
132151898Smckusick 	}
132251898Smckusick 	if (ep->ex_fsdir)
132351898Smckusick 		free(ep->ex_fsdir);
132451898Smckusick 	free_dir(ep->ex_dirl);
132551898Smckusick 	free((caddr_t)ep);
132651898Smckusick }
132751898Smckusick 
132851898Smckusick /*
132951898Smckusick  * Free hosts.
133051898Smckusick  */
133151898Smckusick void
133251898Smckusick free_host(hp)
133366163Spendry 	struct hostlist *hp;
133451898Smckusick {
133566163Spendry 	struct hostlist *hp2;
133651898Smckusick 
133751898Smckusick 	while (hp) {
133851898Smckusick 		hp2 = hp;
133951898Smckusick 		hp = hp->ht_next;
134051898Smckusick 		free((caddr_t)hp2);
134151898Smckusick 	}
134251898Smckusick }
134351898Smckusick 
134451898Smckusick struct hostlist *
134551898Smckusick get_ht()
134651898Smckusick {
134766163Spendry 	struct hostlist *hp;
134851898Smckusick 
134951898Smckusick 	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
135066163Spendry 	if (hp == (struct hostlist *)NULL)
135151898Smckusick 		out_of_mem();
135266163Spendry 	hp->ht_next = (struct hostlist *)NULL;
135351898Smckusick 	return (hp);
135451898Smckusick }
135551898Smckusick 
135651898Smckusick #ifdef ISO
135751898Smckusick /*
135851898Smckusick  * Translate an iso address.
135951898Smckusick  */
136051898Smckusick get_isoaddr(cp, grp)
136151898Smckusick 	char *cp;
136251898Smckusick 	struct grouplist *grp;
136351898Smckusick {
136451898Smckusick 	struct iso_addr *isop;
136551898Smckusick 	struct sockaddr_iso *isoaddr;
136651898Smckusick 
136751898Smckusick 	if (grp->gr_type != GT_NULL)
136851898Smckusick 		return (1);
136951898Smckusick 	if ((isop = iso_addr(cp)) == NULL) {
137051898Smckusick 		syslog(LOG_ERR,
137151898Smckusick 		    "iso_addr failed, ignored");
137251898Smckusick 		return (1);
137351898Smckusick 	}
137451898Smckusick 	isoaddr = (struct sockaddr_iso *)
137551898Smckusick 	    malloc(sizeof (struct sockaddr_iso));
137666163Spendry 	if (isoaddr == (struct sockaddr_iso *)NULL)
137751898Smckusick 		out_of_mem();
137851898Smckusick 	bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
137951898Smckusick 	bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr,
138051898Smckusick 		sizeof (struct iso_addr));
138151898Smckusick 	isoaddr->siso_len = sizeof (struct sockaddr_iso);
138251898Smckusick 	isoaddr->siso_family = AF_ISO;
138351898Smckusick 	grp->gr_type = GT_ISO;
138451898Smckusick 	grp->gr_ptr.gt_isoaddr = isoaddr;
138551898Smckusick 	return (0);
138651898Smckusick }
138751898Smckusick #endif	/* ISO */
138851898Smckusick 
138951898Smckusick /*
139051898Smckusick  * Out of memory, fatal
139151898Smckusick  */
139251898Smckusick void
139351898Smckusick out_of_mem()
139451898Smckusick {
139551898Smckusick 
139651898Smckusick 	syslog(LOG_ERR, "Out of memory");
139751667Smckusick 	exit(2);
139851667Smckusick }
139951667Smckusick 
140051898Smckusick /*
140151898Smckusick  * Do the mount syscall with the update flag to push the export info into
140251898Smckusick  * the kernel.
140351898Smckusick  */
140466163Spendry int
140551898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
140651667Smckusick 	struct exportlist *ep;
140751667Smckusick 	struct grouplist *grp;
140851898Smckusick 	int exflags;
140951667Smckusick 	struct ucred *anoncrp;
141051898Smckusick 	char *dirp;
141151898Smckusick 	int dirplen;
141251898Smckusick 	struct statfs *fsb;
141351667Smckusick {
141466163Spendry 	char *cp = (char *)NULL;
141566163Spendry 	u_long **addrp;
141651898Smckusick 	int done;
141766163Spendry 	char savedc = '\0';
141851898Smckusick 	struct sockaddr_in sin, imask;
141965713Shibler 	union {
142065713Shibler 		struct ufs_args ua;
142165713Shibler 		struct iso_args ia;
142265713Shibler 		struct mfs_args ma;
142365713Shibler 	} args;
142451898Smckusick 	u_long net;
142551667Smckusick 
142665713Shibler 	args.ua.fspec = 0;
142765713Shibler 	args.ua.export.ex_flags = exflags;
142865713Shibler 	args.ua.export.ex_anon = *anoncrp;
142955878Smckusick 	bzero((char *)&sin, sizeof(sin));
143055878Smckusick 	bzero((char *)&imask, sizeof(imask));
143151667Smckusick 	sin.sin_family = AF_INET;
143251667Smckusick 	sin.sin_len = sizeof(sin);
143351898Smckusick 	imask.sin_family = AF_INET;
143451898Smckusick 	imask.sin_len = sizeof(sin);
143551898Smckusick 	if (grp->gr_type == GT_HOST)
143651667Smckusick 		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
143751898Smckusick 	else
143866163Spendry 		addrp = (u_long **)NULL;
143951667Smckusick 	done = FALSE;
144051898Smckusick 	while (!done) {
144151898Smckusick 		switch (grp->gr_type) {
144251898Smckusick 		case GT_HOST:
144364903Smckusick 			if (addrp) {
144451712Smckusick 				sin.sin_addr.s_addr = **addrp;
144565713Shibler 				args.ua.export.ex_addrlen = sizeof(sin);
144664903Smckusick 			} else
144765713Shibler 				args.ua.export.ex_addrlen = 0;
144865713Shibler 			args.ua.export.ex_addr = (struct sockaddr *)&sin;
144965713Shibler 			args.ua.export.ex_masklen = 0;
145051898Smckusick 			break;
145151898Smckusick 		case GT_NET:
145251898Smckusick 			if (grp->gr_ptr.gt_net.nt_mask)
145351898Smckusick 			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
145451898Smckusick 			else {
145551898Smckusick 			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
145651898Smckusick 			    if (IN_CLASSA(net))
145751898Smckusick 				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
145851898Smckusick 			    else if (IN_CLASSB(net))
145951898Smckusick 				imask.sin_addr.s_addr =
146051898Smckusick 				    inet_addr("255.255.0.0");
146151898Smckusick 			    else
146251898Smckusick 				imask.sin_addr.s_addr =
146351898Smckusick 				    inet_addr("255.255.255.0");
146451898Smckusick 			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
146551898Smckusick 			}
146651898Smckusick 			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
146765713Shibler 			args.ua.export.ex_addr = (struct sockaddr *)&sin;
146865713Shibler 			args.ua.export.ex_addrlen = sizeof (sin);
146965713Shibler 			args.ua.export.ex_mask = (struct sockaddr *)&imask;
147065713Shibler 			args.ua.export.ex_masklen = sizeof (imask);
147151898Smckusick 			break;
147251667Smckusick #ifdef ISO
147351898Smckusick 		case GT_ISO:
147465713Shibler 			args.ua.export.ex_addr =
147565713Shibler 				(struct sockaddr *)grp->gr_ptr.gt_isoaddr;
147665713Shibler 			args.ua.export.ex_addrlen =
147765713Shibler 				sizeof(struct sockaddr_iso);
147865713Shibler 			args.ua.export.ex_masklen = 0;
147951898Smckusick 			break;
148051667Smckusick #endif	/* ISO */
148151898Smckusick 		default:
148251667Smckusick 			syslog(LOG_ERR, "Bad grouptype");
148351898Smckusick 			if (cp)
148451898Smckusick 				*cp = savedc;
148551898Smckusick 			return (1);
148651898Smckusick 		};
148752109Smckusick 
148852109Smckusick 		/*
148952109Smckusick 		 * XXX:
149052109Smckusick 		 * Maybe I should just use the fsb->f_mntonname path instead
149152109Smckusick 		 * of looping back up the dirp to the mount point??
149252109Smckusick 		 * Also, needs to know how to export all types of local
149352109Smckusick 		 * exportable file systems and not just MOUNT_UFS.
149452109Smckusick 		 */
149552109Smckusick 		while (mount(fsb->f_type, dirp,
149652109Smckusick 		       fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
149751898Smckusick 			if (cp)
149851898Smckusick 				*cp-- = savedc;
149951898Smckusick 			else
150051898Smckusick 				cp = dirp + dirplen - 1;
150151667Smckusick 			if (errno == EPERM) {
150251667Smckusick 				syslog(LOG_ERR,
150351898Smckusick 				   "Can't change attributes for %s.\n", dirp);
150451898Smckusick 				return (1);
150551667Smckusick 			}
150651898Smckusick 			if (opt_flags & OP_ALLDIRS) {
150751898Smckusick 				syslog(LOG_ERR, "Not root dir");
150851898Smckusick 				return (1);
150951898Smckusick 			}
151051667Smckusick 			/* back up over the last component */
151151898Smckusick 			while (*cp == '/' && cp > dirp)
151251667Smckusick 				cp--;
151351898Smckusick 			while (*(cp - 1) != '/' && cp > dirp)
151451667Smckusick 				cp--;
151551898Smckusick 			if (cp == dirp) {
151651898Smckusick 				if (debug)
151751667Smckusick 					fprintf(stderr,"mnt unsucc\n");
151851898Smckusick 				syslog(LOG_ERR, "Can't export %s", dirp);
151951898Smckusick 				return (1);
152051667Smckusick 			}
152151667Smckusick 			savedc = *cp;
152251667Smckusick 			*cp = '\0';
152351667Smckusick 		}
152451898Smckusick 		if (addrp) {
152551667Smckusick 			++addrp;
152666163Spendry 			if (*addrp == (u_long *)NULL)
152751667Smckusick 				done = TRUE;
152851898Smckusick 		} else
152951898Smckusick 			done = TRUE;
153051898Smckusick 	}
153151898Smckusick 	if (cp)
153251898Smckusick 		*cp = savedc;
153351898Smckusick 	return (0);
153451898Smckusick }
153551898Smckusick 
153651898Smckusick /*
153751898Smckusick  * Translate a net address.
153851898Smckusick  */
153966163Spendry int
154051898Smckusick get_net(cp, net, maskflg)
154151898Smckusick 	char *cp;
154251898Smckusick 	struct netmsk *net;
154351898Smckusick 	int maskflg;
154451898Smckusick {
154566163Spendry 	struct netent *np;
154666163Spendry 	long netaddr;
154751898Smckusick 	struct in_addr inetaddr, inetaddr2;
154851898Smckusick 	char *name;
154951898Smckusick 
155051898Smckusick 	if (np = getnetbyname(cp))
155151898Smckusick 		inetaddr = inet_makeaddr(np->n_net, 0);
155251898Smckusick 	else if (isdigit(*cp)) {
155351898Smckusick 		if ((netaddr = inet_network(cp)) == -1)
155451898Smckusick 			return (1);
155551898Smckusick 		inetaddr = inet_makeaddr(netaddr, 0);
155651898Smckusick 		/*
155751898Smckusick 		 * Due to arbritrary subnet masks, you don't know how many
155851898Smckusick 		 * bits to shift the address to make it into a network,
155951898Smckusick 		 * however you do know how to make a network address into
156051898Smckusick 		 * a host with host == 0 and then compare them.
156151898Smckusick 		 * (What a pest)
156251898Smckusick 		 */
156351898Smckusick 		if (!maskflg) {
156451898Smckusick 			setnetent(0);
156551898Smckusick 			while (np = getnetent()) {
156651898Smckusick 				inetaddr2 = inet_makeaddr(np->n_net, 0);
156751898Smckusick 				if (inetaddr2.s_addr == inetaddr.s_addr)
156851898Smckusick 					break;
156951898Smckusick 			}
157051898Smckusick 			endnetent();
157151667Smckusick 		}
157251898Smckusick 	} else
157351898Smckusick 		return (1);
157451898Smckusick 	if (maskflg)
157551898Smckusick 		net->nt_mask = inetaddr.s_addr;
157651898Smckusick 	else {
157751898Smckusick 		if (np)
157851898Smckusick 			name = np->n_name;
157951898Smckusick 		else
158051898Smckusick 			name = inet_ntoa(inetaddr);
158151898Smckusick 		net->nt_name = (char *)malloc(strlen(name) + 1);
158266163Spendry 		if (net->nt_name == (char *)NULL)
158351898Smckusick 			out_of_mem();
158451898Smckusick 		strcpy(net->nt_name, name);
158551898Smckusick 		net->nt_net = inetaddr.s_addr;
158638460Smckusick 	}
158751898Smckusick 	return (0);
158838460Smckusick }
158938460Smckusick 
159038460Smckusick /*
159138460Smckusick  * Parse out the next white space separated field
159238460Smckusick  */
159351667Smckusick void
159438460Smckusick nextfield(cp, endcp)
159538460Smckusick 	char **cp;
159638460Smckusick 	char **endcp;
159738460Smckusick {
159866163Spendry 	char *p;
159938460Smckusick 
160038460Smckusick 	p = *cp;
160138460Smckusick 	while (*p == ' ' || *p == '\t')
160238460Smckusick 		p++;
160351898Smckusick 	if (*p == '\n' || *p == '\0')
160438460Smckusick 		*cp = *endcp = p;
160551898Smckusick 	else {
160651898Smckusick 		*cp = p++;
160751898Smckusick 		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
160851898Smckusick 			p++;
160951898Smckusick 		*endcp = p;
161038460Smckusick 	}
161138460Smckusick }
161239681Smckusick 
161339681Smckusick /*
161451898Smckusick  * Get an exports file line. Skip over blank lines and handle line
161551898Smckusick  * continuations.
161639681Smckusick  */
161766163Spendry int
161851898Smckusick get_line()
161939681Smckusick {
162066163Spendry 	char *p, *cp;
162166163Spendry 	int len;
162251898Smckusick 	int totlen, cont_line;
162339681Smckusick 
162451898Smckusick 	/*
162551898Smckusick 	 * Loop around ignoring blank lines and getting all continuation lines.
162651898Smckusick 	 */
162751898Smckusick 	p = line;
162851898Smckusick 	totlen = 0;
162951898Smckusick 	do {
163051898Smckusick 		if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
163151898Smckusick 			return (0);
163251898Smckusick 		len = strlen(p);
163351898Smckusick 		cp = p + len - 1;
163451898Smckusick 		cont_line = 0;
163551898Smckusick 		while (cp >= p &&
163651898Smckusick 		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
163751898Smckusick 			if (*cp == '\\')
163851898Smckusick 				cont_line = 1;
163951898Smckusick 			cp--;
164051898Smckusick 			len--;
164151898Smckusick 		}
164251898Smckusick 		*++cp = '\0';
164351898Smckusick 		if (len > 0) {
164451898Smckusick 			totlen += len;
164551898Smckusick 			if (totlen >= LINESIZ) {
164651898Smckusick 				syslog(LOG_ERR, "Exports line too long");
164751898Smckusick 				exit(2);
164851898Smckusick 			}
164951898Smckusick 			p = cp;
165051898Smckusick 		}
165151898Smckusick 	} while (totlen == 0 || cont_line);
165251898Smckusick 	return (1);
165344015Smckusick }
165444015Smckusick 
165551667Smckusick /*
165651667Smckusick  * Parse a description of a credential.
165751667Smckusick  */
165866163Spendry void
165951667Smckusick parsecred(namelist, cr)
166051667Smckusick 	char *namelist;
166166163Spendry 	struct ucred *cr;
166251667Smckusick {
166366163Spendry 	char *name;
166466163Spendry 	int cnt;
166551667Smckusick 	char *names;
166651667Smckusick 	struct passwd *pw;
166751667Smckusick 	struct group *gr;
166851667Smckusick 	int ngroups, groups[NGROUPS + 1];
166951667Smckusick 
167051667Smckusick 	/*
167151667Smckusick 	 * Set up the unpriviledged user.
167251667Smckusick 	 */
167351667Smckusick 	cr->cr_ref = 1;
167451667Smckusick 	cr->cr_uid = -2;
167551667Smckusick 	cr->cr_groups[0] = -2;
167651667Smckusick 	cr->cr_ngroups = 1;
167751667Smckusick 	/*
167851667Smckusick 	 * Get the user's password table entry.
167951667Smckusick 	 */
168051667Smckusick 	names = strsep(&namelist, " \t\n");
168151667Smckusick 	name = strsep(&names, ":");
168251667Smckusick 	if (isdigit(*name) || *name == '-')
168351667Smckusick 		pw = getpwuid(atoi(name));
168451667Smckusick 	else
168551667Smckusick 		pw = getpwnam(name);
168651667Smckusick 	/*
168751667Smckusick 	 * Credentials specified as those of a user.
168851667Smckusick 	 */
168951667Smckusick 	if (names == NULL) {
169051667Smckusick 		if (pw == NULL) {
169166163Spendry 			syslog(LOG_ERR, "Unknown user: %s", name);
169251667Smckusick 			return;
169351667Smckusick 		}
169451667Smckusick 		cr->cr_uid = pw->pw_uid;
169551667Smckusick 		ngroups = NGROUPS + 1;
169651667Smckusick 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
169766163Spendry 			syslog(LOG_ERR, "Too many groups");
169851667Smckusick 		/*
169951667Smckusick 		 * Convert from int's to gid_t's and compress out duplicate
170051667Smckusick 		 */
170151667Smckusick 		cr->cr_ngroups = ngroups - 1;
170251667Smckusick 		cr->cr_groups[0] = groups[0];
170351667Smckusick 		for (cnt = 2; cnt < ngroups; cnt++)
170451667Smckusick 			cr->cr_groups[cnt - 1] = groups[cnt];
170551667Smckusick 		return;
170651667Smckusick 	}
170751667Smckusick 	/*
170851667Smckusick 	 * Explicit credential specified as a colon separated list:
170951667Smckusick 	 *	uid:gid:gid:...
171051667Smckusick 	 */
171151667Smckusick 	if (pw != NULL)
171251667Smckusick 		cr->cr_uid = pw->pw_uid;
171351667Smckusick 	else if (isdigit(*name) || *name == '-')
171451667Smckusick 		cr->cr_uid = atoi(name);
171551667Smckusick 	else {
171666163Spendry 		syslog(LOG_ERR, "Unknown user: %s", name);
171751667Smckusick 		return;
171851667Smckusick 	}
171951667Smckusick 	cr->cr_ngroups = 0;
172051667Smckusick 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
172151667Smckusick 		name = strsep(&names, ":");
172251667Smckusick 		if (isdigit(*name) || *name == '-') {
172351667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
172451667Smckusick 		} else {
172551667Smckusick 			if ((gr = getgrnam(name)) == NULL) {
172666163Spendry 				syslog(LOG_ERR, "Unknown group: %s", name);
172751667Smckusick 				continue;
172851667Smckusick 			}
172951667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
173051667Smckusick 		}
173151667Smckusick 	}
173251667Smckusick 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
173366163Spendry 		syslog(LOG_ERR, "Too many groups");
173451667Smckusick }
173551667Smckusick 
173644015Smckusick #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
173744015Smckusick /*
173844015Smckusick  * Routines that maintain the remote mounttab
173944015Smckusick  */
174051667Smckusick void
174151667Smckusick get_mountlist()
174244015Smckusick {
174366163Spendry 	struct mountlist *mlp, **mlpp;
174466163Spendry 	char *eos, *dirp;
174544015Smckusick 	int len;
174644015Smckusick 	char str[STRSIZ];
174744015Smckusick 	FILE *mlfile;
174844015Smckusick 
174951712Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
175051667Smckusick 		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
175144015Smckusick 		return;
175244015Smckusick 	}
175344015Smckusick 	mlpp = &mlhead;
175444015Smckusick 	while (fgets(str, STRSIZ, mlfile) != NULL) {
175544015Smckusick 		if ((dirp = index(str, '\t')) == NULL &&
175644015Smckusick 		    (dirp = index(str, ' ')) == NULL)
175744015Smckusick 			continue;
175844015Smckusick 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
175944015Smckusick 		len = dirp-str;
176044015Smckusick 		if (len > RPCMNT_NAMELEN)
176144015Smckusick 			len = RPCMNT_NAMELEN;
176244015Smckusick 		bcopy(str, mlp->ml_host, len);
176344015Smckusick 		mlp->ml_host[len] = '\0';
176444015Smckusick 		while (*dirp == '\t' || *dirp == ' ')
176544015Smckusick 			dirp++;
176644015Smckusick 		if ((eos = index(dirp, '\t')) == NULL &&
176744015Smckusick 		    (eos = index(dirp, ' ')) == NULL &&
176844015Smckusick 		    (eos = index(dirp, '\n')) == NULL)
176944015Smckusick 			len = strlen(dirp);
177044015Smckusick 		else
177144015Smckusick 			len = eos-dirp;
177244015Smckusick 		if (len > RPCMNT_PATHLEN)
177344015Smckusick 			len = RPCMNT_PATHLEN;
177444015Smckusick 		bcopy(dirp, mlp->ml_dirp, len);
177544015Smckusick 		mlp->ml_dirp[len] = '\0';
177666163Spendry 		mlp->ml_next = (struct mountlist *)NULL;
177744015Smckusick 		*mlpp = mlp;
177844015Smckusick 		mlpp = &mlp->ml_next;
177944015Smckusick 	}
178044015Smckusick 	fclose(mlfile);
178144015Smckusick }
178244015Smckusick 
178351667Smckusick void
178451667Smckusick del_mlist(hostp, dirp)
178566163Spendry 	char *hostp, *dirp;
178644015Smckusick {
178766163Spendry 	struct mountlist *mlp, **mlpp;
178851712Smckusick 	struct mountlist *mlp2;
178944015Smckusick 	FILE *mlfile;
179044015Smckusick 	int fnd = 0;
179144015Smckusick 
179244015Smckusick 	mlpp = &mlhead;
179344015Smckusick 	mlp = mlhead;
179444015Smckusick 	while (mlp) {
179544015Smckusick 		if (!strcmp(mlp->ml_host, hostp) &&
179644015Smckusick 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
179744015Smckusick 			fnd = 1;
179851712Smckusick 			mlp2 = mlp;
179951712Smckusick 			*mlpp = mlp = mlp->ml_next;
180051712Smckusick 			free((caddr_t)mlp2);
180151712Smckusick 		} else {
180251712Smckusick 			mlpp = &mlp->ml_next;
180351712Smckusick 			mlp = mlp->ml_next;
180439681Smckusick 		}
180539681Smckusick 	}
180644015Smckusick 	if (fnd) {
180744015Smckusick 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
180851898Smckusick 			syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
180944015Smckusick 			return;
181044015Smckusick 		}
181144015Smckusick 		mlp = mlhead;
181244015Smckusick 		while (mlp) {
181344015Smckusick 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
181444015Smckusick 			mlp = mlp->ml_next;
181544015Smckusick 		}
181644015Smckusick 		fclose(mlfile);
181744015Smckusick 	}
181839681Smckusick }
181944015Smckusick 
182051667Smckusick void
182151667Smckusick add_mlist(hostp, dirp)
182266163Spendry 	char *hostp, *dirp;
182344015Smckusick {
182466163Spendry 	struct mountlist *mlp, **mlpp;
182544015Smckusick 	FILE *mlfile;
182644015Smckusick 
182744015Smckusick 	mlpp = &mlhead;
182844015Smckusick 	mlp = mlhead;
182944015Smckusick 	while (mlp) {
183044015Smckusick 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
183144015Smckusick 			return;
183244015Smckusick 		mlpp = &mlp->ml_next;
183344015Smckusick 		mlp = mlp->ml_next;
183444015Smckusick 	}
183544015Smckusick 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
183644015Smckusick 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
183744015Smckusick 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
183844015Smckusick 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
183944015Smckusick 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
184066163Spendry 	mlp->ml_next = (struct mountlist *)NULL;
184144015Smckusick 	*mlpp = mlp;
184244015Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
184351898Smckusick 		syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
184444015Smckusick 		return;
184544015Smckusick 	}
184644015Smckusick 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
184744015Smckusick 	fclose(mlfile);
184844015Smckusick }
184944015Smckusick 
185044015Smckusick /*
185144015Smckusick  * This function is called via. SIGTERM when the system is going down.
185244015Smckusick  * It sends a broadcast RPCMNT_UMNTALL.
185344015Smckusick  */
185446709Sbostic void
185544015Smckusick send_umntall()
185644015Smckusick {
185744015Smckusick 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
185844015Smckusick 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
185951667Smckusick 	exit(0);
186044015Smckusick }
186144015Smckusick 
186266163Spendry int
186344015Smckusick umntall_each(resultsp, raddr)
186444015Smckusick 	caddr_t resultsp;
186544015Smckusick 	struct sockaddr_in *raddr;
186644015Smckusick {
186744015Smckusick 	return (1);
186844015Smckusick }
186944015Smckusick 
187044015Smckusick /*
187151667Smckusick  * Free up a group list.
187251667Smckusick  */
187351667Smckusick void
187451667Smckusick free_grp(grp)
187566163Spendry 	struct grouplist *grp;
187651667Smckusick {
187766163Spendry 	char **addrp;
187851667Smckusick 
187951898Smckusick 	if (grp->gr_type == GT_HOST) {
188051712Smckusick 		if (grp->gr_ptr.gt_hostent->h_name) {
188151712Smckusick 			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
188251712Smckusick 			while (addrp && *addrp)
188351712Smckusick 				free(*addrp++);
188451712Smckusick 			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
188551712Smckusick 			free(grp->gr_ptr.gt_hostent->h_name);
188651712Smckusick 		}
188751667Smckusick 		free((caddr_t)grp->gr_ptr.gt_hostent);
188851898Smckusick 	} else if (grp->gr_type == GT_NET) {
188951898Smckusick 		if (grp->gr_ptr.gt_net.nt_name)
189051898Smckusick 			free(grp->gr_ptr.gt_net.nt_name);
189151667Smckusick 	}
189251667Smckusick #ifdef ISO
189351898Smckusick 	else if (grp->gr_type == GT_ISO)
189451667Smckusick 		free((caddr_t)grp->gr_ptr.gt_isoaddr);
189551667Smckusick #endif
189651667Smckusick 	free((caddr_t)grp);
189751667Smckusick }
189851667Smckusick 
189951711Smckusick #ifdef DEBUG
190051711Smckusick void
190151711Smckusick SYSLOG(int pri, const char *fmt, ...)
190251711Smckusick {
190351711Smckusick 	va_list ap;
190451711Smckusick 
190551711Smckusick 	va_start(ap, fmt);
190651711Smckusick 	vfprintf(stderr, fmt, ap);
190751711Smckusick 	va_end(ap);
190851711Smckusick }
190951711Smckusick #endif /* DEBUG */
191051898Smckusick 
191151898Smckusick /*
191251898Smckusick  * Check options for consistency.
191351898Smckusick  */
191466163Spendry int
191551898Smckusick check_options(dp)
191651898Smckusick 	struct dirlist *dp;
191751898Smckusick {
191851898Smckusick 
191966163Spendry 	if (dp == (struct dirlist *)NULL)
192051898Smckusick 	    return (1);
192151898Smckusick 	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
192251898Smckusick 	    (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
192351898Smckusick 	    (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
192451898Smckusick 	    syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
192551898Smckusick 	    return (1);
192651898Smckusick 	}
192751898Smckusick 	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
192851898Smckusick 	    syslog(LOG_ERR, "-mask requires -net");
192951898Smckusick 	    return (1);
193051898Smckusick 	}
193151898Smckusick 	if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
193251898Smckusick 	    syslog(LOG_ERR, "-net and -iso mutually exclusive");
193351898Smckusick 	    return (1);
193451898Smckusick 	}
193551898Smckusick 	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
193651898Smckusick 	    syslog(LOG_ERR, "-alldir has multiple directories");
193751898Smckusick 	    return (1);
193851898Smckusick 	}
193951898Smckusick 	return (0);
194051898Smckusick }
194165940Sbostic 
194265940Sbostic /*
194365940Sbostic  * Check an absolute directory path for any symbolic links. Return true
194465940Sbostic  * if no symbolic links are found.
194565940Sbostic  */
194665940Sbostic int
194765940Sbostic check_dirpath(dirp)
194866163Spendry 	char *dirp;
194965940Sbostic {
195066163Spendry 	char *cp;
195165940Sbostic 	int ret = 1;
195265940Sbostic 	struct stat sb;
195365940Sbostic 
195465940Sbostic 	cp = dirp + 1;
195565940Sbostic 	while (*cp && ret) {
195665940Sbostic 		if (*cp == '/') {
195765940Sbostic 			*cp = '\0';
195867383Smkm 			if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
195965940Sbostic 				ret = 0;
196065940Sbostic 			*cp = '/';
196165940Sbostic 		}
196265940Sbostic 		cp++;
196365940Sbostic 	}
196467383Smkm 	if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
196565940Sbostic 		ret = 0;
196665940Sbostic 	return (ret);
196765940Sbostic }
1968