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