Home | History | Annotate | Line # | Download | only in mountd
mountd.c revision 1.1
      1 /*
      2  * Copyright (c) 1989 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * This code is derived from software contributed to Berkeley by
      6  * Rick Macklem at The University of Guelph.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by the University of
     19  *	California, Berkeley and its contributors.
     20  * 4. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  */
     36 
     37 #ifndef lint
     38 char copyright[] =
     39 "@(#) Copyright (c) 1989 Regents of the University of California.\n\
     40  All rights reserved.\n";
     41 #endif not lint
     42 
     43 #ifndef lint
     44 static char sccsid[] = "@(#)mountd.c	5.14 (Berkeley) 2/26/91";
     45 #endif not lint
     46 
     47 #include <sys/param.h>
     48 #include <sys/ioctl.h>
     49 #include <sys/stat.h>
     50 #include <sys/file.h>
     51 #include <sys/mount.h>
     52 #include <sys/socket.h>
     53 #include <sys/errno.h>
     54 #include <sys/signal.h>
     55 #include <stdio.h>
     56 #include <string.h>
     57 #include <syslog.h>
     58 #include <netdb.h>
     59 #include <rpc/rpc.h>
     60 #include <rpc/pmap_clnt.h>
     61 #include <rpc/pmap_prot.h>
     62 #include <nfs/rpcv2.h>
     63 #include <nfs/nfsv2.h>
     64 #include "pathnames.h"
     65 
     66 struct ufid {
     67 	u_short	ufid_len;
     68 	ino_t	ufid_ino;
     69 	long	ufid_gen;
     70 };
     71 /*
     72  * Structures for keeping the mount list and export list
     73  */
     74 struct mountlist {
     75 	struct mountlist *ml_next;
     76 	char	ml_host[RPCMNT_NAMELEN+1];
     77 	char	ml_dirp[RPCMNT_PATHLEN+1];
     78 };
     79 
     80 struct exportlist {
     81 	struct exportlist *ex_next;
     82 	struct exportlist *ex_prev;
     83 	struct grouplist *ex_groups;
     84 	int	ex_rootuid;
     85 	int	ex_exflags;
     86 	dev_t	ex_dev;
     87 	char	ex_dirp[RPCMNT_PATHLEN+1];
     88 };
     89 
     90 struct grouplist {
     91 	struct grouplist *gr_next;
     92 	struct hostent *gr_hp;
     93 };
     94 
     95 /* Global defs */
     96 int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
     97 void add_mlist(), del_mlist(), get_exportlist(), get_mountlist();
     98 void send_umntall();
     99 struct exportlist exphead;
    100 struct mountlist *mlhead;
    101 char exname[MAXPATHLEN];
    102 int def_rootuid = -2;
    103 int root_only = 1;
    104 extern int errno;
    105 #ifdef DEBUG
    106 int debug = 1;
    107 #else
    108 int debug = 0;
    109 #endif
    110 
    111 /*
    112  * Mountd server for NFS mount protocol as described in:
    113  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
    114  * The optional arguments are the exports file name
    115  * default: _PATH_EXPORTS
    116  * and "-n" to allow nonroot mount.
    117  */
    118 main(argc, argv)
    119 	int argc;
    120 	char **argv;
    121 {
    122 	SVCXPRT *transp;
    123 	int c;
    124 	extern int optind;
    125 	extern char *optarg;
    126 
    127 	while ((c = getopt(argc, argv, "n")) != EOF)
    128 		switch (c) {
    129 		case 'n':
    130 			root_only = 0;
    131 			break;
    132 		default:
    133 			fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
    134 			exit(1);
    135 		};
    136 	argc -= optind;
    137 	argv += optind;
    138 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
    139 	mlhead = (struct mountlist *)0;
    140 	if (argc == 1) {
    141 		strncpy(exname, *argv, MAXPATHLEN-1);
    142 		exname[MAXPATHLEN-1] = '\0';
    143 	} else
    144 		strcpy(exname, _PATH_EXPORTS);
    145 	openlog("mountd:", LOG_PID, LOG_DAEMON);
    146 	get_exportlist();
    147 	get_mountlist();
    148 	if (debug == 0) {
    149 		daemon(0, 0);
    150 		signal(SIGINT, SIG_IGN);
    151 		signal(SIGQUIT, SIG_IGN);
    152 	}
    153 	signal(SIGHUP, get_exportlist);
    154 	signal(SIGTERM, send_umntall);
    155 	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
    156 	  if (pidfile != NULL) {
    157 		fprintf(pidfile, "%d\n", getpid());
    158 		fclose(pidfile);
    159 	  }
    160 	}
    161 	if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
    162 		syslog(LOG_ERR, "Can't create socket");
    163 		exit(1);
    164 	}
    165 	pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
    166 	if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_UDP)) {
    167 		syslog(LOG_ERR, "Can't register mount");
    168 		exit(1);
    169 	}
    170 	svc_run();
    171 	syslog(LOG_ERR, "Mountd died");
    172 	exit(1);
    173 }
    174 
    175 /*
    176  * The mount rpc service
    177  */
    178 mntsrv(rqstp, transp)
    179 	register struct svc_req *rqstp;
    180 	register SVCXPRT *transp;
    181 {
    182 	register struct grouplist *grp;
    183 	register u_long **addrp;
    184 	register struct exportlist *ep;
    185 	nfsv2fh_t nfh;
    186 	struct authunix_parms *ucr;
    187 	struct stat stb;
    188 	struct hostent *hp;
    189 	u_long saddr;
    190 	char dirpath[RPCMNT_PATHLEN+1];
    191 	int bad = ENOENT;
    192 	int omask;
    193 	uid_t uid = -2;
    194 
    195 	/* Get authorization */
    196 	switch (rqstp->rq_cred.oa_flavor) {
    197 	case AUTH_UNIX:
    198 		ucr = (struct authunix_parms *)rqstp->rq_clntcred;
    199 		uid = ucr->aup_uid;
    200 		break;
    201 	case AUTH_NULL:
    202 	default:
    203 		break;
    204 	}
    205 
    206 	saddr = transp->xp_raddr.sin_addr.s_addr;
    207 	hp = (struct hostent *)0;
    208 	switch (rqstp->rq_proc) {
    209 	case NULLPROC:
    210 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
    211 			syslog(LOG_ERR, "Can't send reply");
    212 		return;
    213 	case RPCMNT_MOUNT:
    214 		if (uid != 0 && root_only) {
    215 			svcerr_weakauth(transp);
    216 			return;
    217 		}
    218 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
    219 			svcerr_decode(transp);
    220 			return;
    221 		}
    222 
    223 		/* Check to see if it's a valid dirpath */
    224 		if (stat(dirpath, &stb) < 0 || (stb.st_mode&S_IFMT) !=
    225 			S_IFDIR) {
    226 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
    227 				syslog(LOG_ERR, "Can't send reply");
    228 			return;
    229 		}
    230 
    231 		/* Check in the exports list */
    232 		omask = sigblock(sigmask(SIGHUP));
    233 		ep = exphead.ex_next;
    234 		while (ep != NULL) {
    235 			if (!strcmp(ep->ex_dirp, dirpath)) {
    236 				grp = ep->ex_groups;
    237 				if (grp == NULL)
    238 					break;
    239 
    240 				/* Check for a host match */
    241 				addrp = (u_long **)grp->gr_hp->h_addr_list;
    242 				for (;;) {
    243 					if (**addrp == saddr)
    244 						break;
    245 					if (*++addrp == NULL)
    246 						if (grp = grp->gr_next) {
    247 							addrp = (u_long **)
    248 								grp->gr_hp->h_addr_list;
    249 						} else {
    250 							bad = EACCES;
    251 							if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
    252 								syslog(LOG_ERR, "Can't send reply");
    253 							sigsetmask(omask);
    254 							return;
    255 						}
    256 				}
    257 				hp = grp->gr_hp;
    258 				break;
    259 			}
    260 			ep = ep->ex_next;
    261 		}
    262 		sigsetmask(omask);
    263 		if (ep == NULL) {
    264 			bad = EACCES;
    265 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
    266 				syslog(LOG_ERR, "Can't send reply");
    267 			return;
    268 		}
    269 
    270 		/* Get the file handle */
    271 		bzero((caddr_t)&nfh, sizeof(nfh));
    272 		if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
    273 			bad = errno;
    274 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
    275 				syslog(LOG_ERR, "Can't send reply");
    276 			return;
    277 		}
    278 		if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
    279 			syslog(LOG_ERR, "Can't send reply");
    280 		if (hp == NULL)
    281 			hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
    282 		if (hp)
    283 			add_mlist(hp->h_name, dirpath);
    284 		return;
    285 	case RPCMNT_DUMP:
    286 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
    287 			syslog(LOG_ERR, "Can't send reply");
    288 		return;
    289 	case RPCMNT_UMOUNT:
    290 		if (uid != 0 && root_only) {
    291 			svcerr_weakauth(transp);
    292 			return;
    293 		}
    294 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
    295 			svcerr_decode(transp);
    296 			return;
    297 		}
    298 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
    299 			syslog(LOG_ERR, "Can't send reply");
    300 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
    301 		if (hp)
    302 			del_mlist(hp->h_name, dirpath);
    303 		return;
    304 	case RPCMNT_UMNTALL:
    305 		if (uid != 0 && root_only) {
    306 			svcerr_weakauth(transp);
    307 			return;
    308 		}
    309 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
    310 			syslog(LOG_ERR, "Can't send reply");
    311 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
    312 		if (hp)
    313 			del_mlist(hp->h_name, (char *)0);
    314 		return;
    315 	case RPCMNT_EXPORT:
    316 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)0))
    317 			syslog(LOG_ERR, "Can't send reply");
    318 		return;
    319 	default:
    320 		svcerr_noproc(transp);
    321 		return;
    322 	}
    323 }
    324 
    325 /*
    326  * Xdr conversion for a dirpath string
    327  */
    328 xdr_dir(xdrsp, dirp)
    329 	XDR *xdrsp;
    330 	char *dirp;
    331 {
    332 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
    333 }
    334 
    335 /*
    336  * Xdr routine to generate fhstatus
    337  */
    338 xdr_fhs(xdrsp, nfh)
    339 	XDR *xdrsp;
    340 	nfsv2fh_t *nfh;
    341 {
    342 	int ok = 0;
    343 
    344 	if (!xdr_long(xdrsp, &ok))
    345 		return (0);
    346 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
    347 }
    348 
    349 xdr_mlist(xdrsp, cp)
    350 	XDR *xdrsp;
    351 	caddr_t cp;
    352 {
    353 	register struct mountlist *mlp;
    354 	int true = 1;
    355 	int false = 0;
    356 	char *strp;
    357 
    358 	mlp = mlhead;
    359 	while (mlp) {
    360 		if (!xdr_bool(xdrsp, &true))
    361 			return (0);
    362 		strp = &mlp->ml_host[0];
    363 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
    364 			return (0);
    365 		strp = &mlp->ml_dirp[0];
    366 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
    367 			return (0);
    368 		mlp = mlp->ml_next;
    369 	}
    370 	if (!xdr_bool(xdrsp, &false))
    371 		return (0);
    372 	return (1);
    373 }
    374 
    375 /*
    376  * Xdr conversion for export list
    377  */
    378 xdr_explist(xdrsp, cp)
    379 	XDR *xdrsp;
    380 	caddr_t cp;
    381 {
    382 	register struct exportlist *ep;
    383 	register struct grouplist *grp;
    384 	int true = 1;
    385 	int false = 0;
    386 	char *strp;
    387 	int omask;
    388 
    389 	omask = sigblock(sigmask(SIGHUP));
    390 	ep = exphead.ex_next;
    391 	while (ep != NULL) {
    392 		if (!xdr_bool(xdrsp, &true))
    393 			goto errout;
    394 		strp = &ep->ex_dirp[0];
    395 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
    396 			goto errout;
    397 		grp = ep->ex_groups;
    398 		while (grp != NULL) {
    399 			if (!xdr_bool(xdrsp, &true))
    400 				goto errout;
    401 			strp = grp->gr_hp->h_name;
    402 			if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
    403 				goto errout;
    404 			grp = grp->gr_next;
    405 		}
    406 		if (!xdr_bool(xdrsp, &false))
    407 			goto errout;
    408 		ep = ep->ex_next;
    409 	}
    410 	sigsetmask(omask);
    411 	if (!xdr_bool(xdrsp, &false))
    412 		return (0);
    413 	return (1);
    414 errout:
    415 	sigsetmask(omask);
    416 	return (0);
    417 }
    418 
    419 #define LINESIZ	10240
    420 char line[LINESIZ];
    421 
    422 /*
    423  * Get the export list
    424  */
    425 void
    426 get_exportlist()
    427 {
    428 	register struct hostent *hp, *nhp;
    429 	register char **addrp, **naddrp;
    430 	register int i;
    431 	register struct grouplist *grp;
    432 	register struct exportlist *ep, *ep2;
    433 	struct statfs stfsbuf;
    434 	struct ufs_args args;
    435 	struct stat sb;
    436 	FILE *inf;
    437 	char *cp, *endcp;
    438 	char savedc;
    439 	int len, dirplen;
    440 	int rootuid, exflags;
    441 	u_long saddr;
    442 	struct exportlist *fep;
    443 
    444 	/*
    445 	 * First, get rid of the old list
    446 	 */
    447 	ep = exphead.ex_next;
    448 	while (ep != NULL) {
    449 		ep2 = ep;
    450 		ep = ep->ex_next;
    451 		free_exp(ep2);
    452 	}
    453 
    454 	/*
    455 	 * Read in the exports file and build the list, calling
    456 	 * exportfs() as we go along
    457 	 */
    458 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
    459 	if ((inf = fopen(exname, "r")) == NULL) {
    460 		syslog(LOG_ERR, "Can't open %s", exname);
    461 		exit(2);
    462 	}
    463 	while (fgets(line, LINESIZ, inf)) {
    464 		exflags = MNT_EXPORTED;
    465 		rootuid = def_rootuid;
    466 		cp = line;
    467 		nextfield(&cp, &endcp);
    468 
    469 		/*
    470 		 * Get file system devno and see if an entry for this
    471 		 * file system already exists.
    472 		 */
    473 		savedc = *endcp;
    474 		*endcp = '\0';
    475 		if (stat(cp, &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFDIR) {
    476 			syslog(LOG_ERR,
    477 			    "Bad Exports File, %s: %s, mountd Failed",
    478 			    cp, "Not a directory");
    479 			exit(2);
    480 		}
    481 		fep = (struct exportlist *)0;
    482 		ep = exphead.ex_next;
    483 		while (ep) {
    484 			if (ep->ex_dev == sb.st_dev) {
    485 				fep = ep;
    486 				break;
    487 			}
    488 			ep = ep->ex_next;
    489 		}
    490 		*endcp = savedc;
    491 
    492 		/*
    493 		 * Create new exports list entry
    494 		 */
    495 		len = endcp-cp;
    496 		if (len <= RPCMNT_PATHLEN && len > 0) {
    497 			ep = (struct exportlist *)malloc(sizeof(*ep));
    498 			if (ep == NULL)
    499 				goto err;
    500 			ep->ex_next = ep->ex_prev = (struct exportlist *)0;
    501 			ep->ex_groups = (struct grouplist *)0;
    502 			bcopy(cp, ep->ex_dirp, len);
    503 			ep->ex_dirp[len] = '\0';
    504 			dirplen = len;
    505 		} else {
    506 			syslog(LOG_ERR, "Bad Exports File, mountd Failed");
    507 			exit(2);
    508 		}
    509 		cp = endcp;
    510 		nextfield(&cp, &endcp);
    511 		len = endcp-cp;
    512 		while (len > 0) {
    513 			savedc = *endcp;
    514 			*endcp = '\0';
    515 			if (len > RPCMNT_NAMELEN)
    516 				goto more;
    517 			if (*cp == '-') {
    518 				do_opt(cp + 1, fep, ep, &exflags, &rootuid);
    519 				goto more;
    520 			}
    521 			if (isdigit(*cp)) {
    522 				saddr = inet_addr(cp);
    523 				if (saddr == -1 ||
    524 				    (hp = gethostbyaddr((caddr_t)&saddr,
    525 				     sizeof(saddr), AF_INET)) == NULL) {
    526 					syslog(LOG_ERR,
    527 					    "Bad Exports File, %s: %s", cp,
    528 					    "Gethostbyaddr failed, ignored");
    529 					goto more;
    530 				}
    531 			} else if ((hp = gethostbyname(cp)) == NULL) {
    532 				syslog(LOG_ERR, "Bad Exports File, %s: %s",
    533 				    cp, "Gethostbyname failed, ignored");
    534 				goto more;
    535 			}
    536 			grp = (struct grouplist *)
    537 				malloc(sizeof(struct grouplist));
    538 			if (grp == NULL)
    539 				goto err;
    540 			nhp = grp->gr_hp = (struct hostent *)
    541 				malloc(sizeof(struct hostent));
    542 			if (nhp == NULL)
    543 				goto err;
    544 			bcopy((caddr_t)hp, (caddr_t)nhp,
    545 				sizeof(struct hostent));
    546 			i = strlen(hp->h_name)+1;
    547 			nhp->h_name = (char *)malloc(i);
    548 			if (nhp->h_name == NULL)
    549 				goto err;
    550 			bcopy(hp->h_name, nhp->h_name, i);
    551 			addrp = hp->h_addr_list;
    552 			i = 1;
    553 			while (*addrp++)
    554 				i++;
    555 			naddrp = nhp->h_addr_list = (char **)
    556 				malloc(i*sizeof(char *));
    557 			if (naddrp == NULL)
    558 				goto err;
    559 			addrp = hp->h_addr_list;
    560 			while (*addrp) {
    561 				*naddrp = (char *)
    562 				    malloc(hp->h_length);
    563 				if (*naddrp == NULL)
    564 				    goto err;
    565 				bcopy(*addrp, *naddrp,
    566 					hp->h_length);
    567 				addrp++;
    568 				naddrp++;
    569 			}
    570 			*naddrp = (char *)0;
    571 			grp->gr_next = ep->ex_groups;
    572 			ep->ex_groups = grp;
    573 		more:
    574 			cp = endcp;
    575 			*cp = savedc;
    576 			nextfield(&cp, &endcp);
    577 			len = endcp - cp;
    578 		}
    579 		if (fep == NULL) {
    580 			args.fspec = 0;
    581 			args.exflags = exflags;
    582 			args.exroot = rootuid;
    583 			cp = (char *)0;
    584 			while (statfs(ep->ex_dirp, &stfsbuf) < 0 ||
    585 			       mount(MOUNT_UFS, ep->ex_dirp,
    586 				     stfsbuf.f_flags|MNT_UPDATE, &args) < 0) {
    587 				if (cp == NULL)
    588 					cp = ep->ex_dirp + dirplen - 1;
    589 				else
    590 					*cp = savedc;
    591 				/* back up over the last component */
    592 				while (*cp == '/' && cp > ep->ex_dirp)
    593 					cp--;
    594 				while (*(cp - 1) != '/' && cp > ep->ex_dirp)
    595 					cp--;
    596 				if (cp == ep->ex_dirp) {
    597 					syslog(LOG_WARNING,
    598 					      "Can't export %s", ep->ex_dirp);
    599 					free_exp(ep);
    600 					goto nextline;
    601 				}
    602 				savedc = *cp;
    603 				*cp = '\0';
    604 			}
    605 			if (cp)
    606 				*cp = savedc;
    607 			ep->ex_rootuid = rootuid;
    608 			ep->ex_exflags = exflags;
    609 		} else {
    610 			ep->ex_rootuid = fep->ex_rootuid;
    611 			ep->ex_exflags = fep->ex_exflags;
    612 		}
    613 		ep->ex_dev = sb.st_dev;
    614 		ep->ex_next = exphead.ex_next;
    615 		ep->ex_prev = &exphead;
    616 		if (ep->ex_next != NULL)
    617 			ep->ex_next->ex_prev = ep;
    618 		exphead.ex_next = ep;
    619 nextline:
    620 		;
    621 	}
    622 	fclose(inf);
    623 	return;
    624 err:
    625 	syslog(LOG_ERR, "No more memory: mountd Failed");
    626 	exit(2);
    627 }
    628 
    629 /*
    630  * Parse out the next white space separated field
    631  */
    632 nextfield(cp, endcp)
    633 	char **cp;
    634 	char **endcp;
    635 {
    636 	register char *p;
    637 
    638 	p = *cp;
    639 	while (*p == ' ' || *p == '\t')
    640 		p++;
    641 	if (*p == '\n' || *p == '\0') {
    642 		*cp = *endcp = p;
    643 		return;
    644 	}
    645 	*cp = p++;
    646 	while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
    647 		p++;
    648 	*endcp = p;
    649 }
    650 
    651 /*
    652  * Parse the option string
    653  */
    654 do_opt(cpopt, fep, ep, exflagsp, rootuidp)
    655 	register char *cpopt;
    656 	struct exportlist *fep, *ep;
    657 	int *exflagsp, *rootuidp;
    658 {
    659 	register char *cpoptarg, *cpoptend;
    660 
    661 	while (cpopt && *cpopt) {
    662 		if (cpoptend = index(cpopt, ','))
    663 			*cpoptend++ = '\0';
    664 		if (cpoptarg = index(cpopt, '='))
    665 			*cpoptarg++ = '\0';
    666 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
    667 			if (fep && (fep->ex_exflags & MNT_EXRDONLY) == 0)
    668 				syslog(LOG_WARNING, "ro failed for %s",
    669 				       ep->ex_dirp);
    670 			else
    671 				*exflagsp |= MNT_EXRDONLY;
    672 		} else if (!strcmp(cpopt, "root") || !strcmp(cpopt, "r")) {
    673 			if (cpoptarg && isdigit(*cpoptarg)) {
    674 				*rootuidp = atoi(cpoptarg);
    675 				if (fep && fep->ex_rootuid != *rootuidp)
    676 					syslog(LOG_WARNING,
    677 					       "uid failed for %s",
    678 					       ep->ex_dirp);
    679 			} else
    680 				syslog(LOG_WARNING,
    681 				       "uid failed for %s",
    682 				       ep->ex_dirp);
    683 		} else
    684 			syslog(LOG_WARNING, "opt %s ignored for %s", cpopt,
    685 			       ep->ex_dirp);
    686 		cpopt = cpoptend;
    687 	}
    688 }
    689 
    690 #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
    691 /*
    692  * Routines that maintain the remote mounttab
    693  */
    694 void get_mountlist()
    695 {
    696 	register struct mountlist *mlp, **mlpp;
    697 	register char *eos, *dirp;
    698 	int len;
    699 	char str[STRSIZ];
    700 	FILE *mlfile;
    701 
    702 	if (((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) &&
    703 	    ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL)) {
    704 		syslog(LOG_WARNING, "Can't open %s", _PATH_RMOUNTLIST);
    705 		return;
    706 	}
    707 	mlpp = &mlhead;
    708 	while (fgets(str, STRSIZ, mlfile) != NULL) {
    709 		if ((dirp = index(str, '\t')) == NULL &&
    710 		    (dirp = index(str, ' ')) == NULL)
    711 			continue;
    712 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
    713 		len = dirp-str;
    714 		if (len > RPCMNT_NAMELEN)
    715 			len = RPCMNT_NAMELEN;
    716 		bcopy(str, mlp->ml_host, len);
    717 		mlp->ml_host[len] = '\0';
    718 		while (*dirp == '\t' || *dirp == ' ')
    719 			dirp++;
    720 		if ((eos = index(dirp, '\t')) == NULL &&
    721 		    (eos = index(dirp, ' ')) == NULL &&
    722 		    (eos = index(dirp, '\n')) == NULL)
    723 			len = strlen(dirp);
    724 		else
    725 			len = eos-dirp;
    726 		if (len > RPCMNT_PATHLEN)
    727 			len = RPCMNT_PATHLEN;
    728 		bcopy(dirp, mlp->ml_dirp, len);
    729 		mlp->ml_dirp[len] = '\0';
    730 		mlp->ml_next = (struct mountlist *)0;
    731 		*mlpp = mlp;
    732 		mlpp = &mlp->ml_next;
    733 	}
    734 	fclose(mlfile);
    735 }
    736 
    737 void del_mlist(hostp, dirp)
    738 	register char *hostp, *dirp;
    739 {
    740 	register struct mountlist *mlp, **mlpp;
    741 	FILE *mlfile;
    742 	int fnd = 0;
    743 
    744 	mlpp = &mlhead;
    745 	mlp = mlhead;
    746 	while (mlp) {
    747 		if (!strcmp(mlp->ml_host, hostp) &&
    748 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
    749 			fnd = 1;
    750 			*mlpp = mlp->ml_next;
    751 			free((caddr_t)mlp);
    752 		}
    753 		mlpp = &mlp->ml_next;
    754 		mlp = mlp->ml_next;
    755 	}
    756 	if (fnd) {
    757 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
    758 			syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
    759 			return;
    760 		}
    761 		mlp = mlhead;
    762 		while (mlp) {
    763 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
    764 			mlp = mlp->ml_next;
    765 		}
    766 		fclose(mlfile);
    767 	}
    768 }
    769 
    770 void add_mlist(hostp, dirp)
    771 	register char *hostp, *dirp;
    772 {
    773 	register struct mountlist *mlp, **mlpp;
    774 	FILE *mlfile;
    775 
    776 	mlpp = &mlhead;
    777 	mlp = mlhead;
    778 	while (mlp) {
    779 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
    780 			return;
    781 		mlpp = &mlp->ml_next;
    782 		mlp = mlp->ml_next;
    783 	}
    784 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
    785 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
    786 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
    787 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
    788 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
    789 	mlp->ml_next = (struct mountlist *)0;
    790 	*mlpp = mlp;
    791 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
    792 		syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
    793 		return;
    794 	}
    795 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
    796 	fclose(mlfile);
    797 }
    798 
    799 /*
    800  * This function is called via. SIGTERM when the system is going down.
    801  * It sends a broadcast RPCMNT_UMNTALL.
    802  */
    803 void
    804 send_umntall()
    805 {
    806 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
    807 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
    808 	exit();
    809 }
    810 
    811 umntall_each(resultsp, raddr)
    812 	caddr_t resultsp;
    813 	struct sockaddr_in *raddr;
    814 {
    815 	return (1);
    816 }
    817 
    818 /*
    819  * Free up an exports list component
    820  */
    821 free_exp(ep)
    822 	register struct exportlist *ep;
    823 {
    824 	register struct grouplist *grp;
    825 	register char **addrp;
    826 	struct grouplist *grp2;
    827 
    828 	grp = ep->ex_groups;
    829 	while (grp != NULL) {
    830 		addrp = grp->gr_hp->h_addr_list;
    831 		while (*addrp)
    832 			free(*addrp++);
    833 		free((caddr_t)grp->gr_hp->h_addr_list);
    834 		free(grp->gr_hp->h_name);
    835 		free((caddr_t)grp->gr_hp);
    836 		grp2 = grp;
    837 		grp = grp->gr_next;
    838 		free((caddr_t)grp2);
    839 	}
    840 	free((caddr_t)ep);
    841 }
    842