xref: /original-bsd/sbin/mountd/mountd.c (revision 95a66346)
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.14 (Berkeley) 02/26/91";
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 mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
71 void add_mlist(), del_mlist(), get_exportlist(), get_mountlist();
72 void send_umntall();
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 void
400 get_exportlist()
401 {
402 	register struct hostent *hp, *nhp;
403 	register char **addrp, **naddrp;
404 	register int i;
405 	register struct grouplist *grp;
406 	register struct exportlist *ep, *ep2;
407 	struct statfs stfsbuf;
408 	struct ufs_args args;
409 	struct stat sb;
410 	FILE *inf;
411 	char *cp, *endcp;
412 	char savedc;
413 	int len, dirplen;
414 	int rootuid, exflags;
415 	u_long saddr;
416 	struct exportlist *fep;
417 
418 	/*
419 	 * First, get rid of the old list
420 	 */
421 	ep = exphead.ex_next;
422 	while (ep != NULL) {
423 		ep2 = ep;
424 		ep = ep->ex_next;
425 		free_exp(ep2);
426 	}
427 
428 	/*
429 	 * Read in the exports file and build the list, calling
430 	 * exportfs() as we go along
431 	 */
432 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
433 	if ((inf = fopen(exname, "r")) == NULL) {
434 		syslog(LOG_ERR, "Can't open %s", exname);
435 		exit(2);
436 	}
437 	while (fgets(line, LINESIZ, inf)) {
438 		exflags = MNT_EXPORTED;
439 		rootuid = def_rootuid;
440 		cp = line;
441 		nextfield(&cp, &endcp);
442 
443 		/*
444 		 * Get file system devno and see if an entry for this
445 		 * file system already exists.
446 		 */
447 		savedc = *endcp;
448 		*endcp = '\0';
449 		if (stat(cp, &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFDIR) {
450 			syslog(LOG_ERR,
451 			    "Bad Exports File, %s: %s, mountd Failed",
452 			    cp, "Not a directory");
453 			exit(2);
454 		}
455 		fep = (struct exportlist *)0;
456 		ep = exphead.ex_next;
457 		while (ep) {
458 			if (ep->ex_dev == sb.st_dev) {
459 				fep = ep;
460 				break;
461 			}
462 			ep = ep->ex_next;
463 		}
464 		*endcp = savedc;
465 
466 		/*
467 		 * Create new exports list entry
468 		 */
469 		len = endcp-cp;
470 		if (len <= RPCMNT_PATHLEN && len > 0) {
471 			ep = (struct exportlist *)malloc(sizeof(*ep));
472 			if (ep == NULL)
473 				goto err;
474 			ep->ex_next = ep->ex_prev = (struct exportlist *)0;
475 			ep->ex_groups = (struct grouplist *)0;
476 			bcopy(cp, ep->ex_dirp, len);
477 			ep->ex_dirp[len] = '\0';
478 			dirplen = len;
479 		} else {
480 			syslog(LOG_ERR, "Bad Exports File, mountd Failed");
481 			exit(2);
482 		}
483 		cp = endcp;
484 		nextfield(&cp, &endcp);
485 		len = endcp-cp;
486 		while (len > 0) {
487 			savedc = *endcp;
488 			*endcp = '\0';
489 			if (len > RPCMNT_NAMELEN)
490 				goto more;
491 			if (*cp == '-') {
492 				do_opt(cp + 1, fep, ep, &exflags, &rootuid);
493 				goto more;
494 			}
495 			if (isdigit(*cp)) {
496 				saddr = inet_addr(cp);
497 				if (saddr == -1 ||
498 				    (hp = gethostbyaddr((caddr_t)&saddr,
499 				     sizeof(saddr), AF_INET)) == NULL) {
500 					syslog(LOG_ERR,
501 					    "Bad Exports File, %s: %s", cp,
502 					    "Gethostbyaddr failed, ignored");
503 					goto more;
504 				}
505 			} else if ((hp = gethostbyname(cp)) == NULL) {
506 				syslog(LOG_ERR, "Bad Exports File, %s: %s",
507 				    cp, "Gethostbyname failed, ignored");
508 				goto more;
509 			}
510 			grp = (struct grouplist *)
511 				malloc(sizeof(struct grouplist));
512 			if (grp == NULL)
513 				goto err;
514 			nhp = grp->gr_hp = (struct hostent *)
515 				malloc(sizeof(struct hostent));
516 			if (nhp == NULL)
517 				goto err;
518 			bcopy((caddr_t)hp, (caddr_t)nhp,
519 				sizeof(struct hostent));
520 			i = strlen(hp->h_name)+1;
521 			nhp->h_name = (char *)malloc(i);
522 			if (nhp->h_name == NULL)
523 				goto err;
524 			bcopy(hp->h_name, nhp->h_name, i);
525 			addrp = hp->h_addr_list;
526 			i = 1;
527 			while (*addrp++)
528 				i++;
529 			naddrp = nhp->h_addr_list = (char **)
530 				malloc(i*sizeof(char *));
531 			if (naddrp == NULL)
532 				goto err;
533 			addrp = hp->h_addr_list;
534 			while (*addrp) {
535 				*naddrp = (char *)
536 				    malloc(hp->h_length);
537 				if (*naddrp == NULL)
538 				    goto err;
539 				bcopy(*addrp, *naddrp,
540 					hp->h_length);
541 				addrp++;
542 				naddrp++;
543 			}
544 			*naddrp = (char *)0;
545 			grp->gr_next = ep->ex_groups;
546 			ep->ex_groups = grp;
547 		more:
548 			cp = endcp;
549 			*cp = savedc;
550 			nextfield(&cp, &endcp);
551 			len = endcp - cp;
552 		}
553 		if (fep == NULL) {
554 			args.fspec = 0;
555 			args.exflags = exflags;
556 			args.exroot = rootuid;
557 			cp = (char *)0;
558 			while (statfs(ep->ex_dirp, &stfsbuf) < 0 ||
559 			       mount(MOUNT_UFS, ep->ex_dirp,
560 				     stfsbuf.f_flags|MNT_UPDATE, &args) < 0) {
561 				if (cp == NULL)
562 					cp = ep->ex_dirp + dirplen - 1;
563 				else
564 					*cp = savedc;
565 				/* back up over the last component */
566 				while (*cp == '/' && cp > ep->ex_dirp)
567 					cp--;
568 				while (*(cp - 1) != '/' && cp > ep->ex_dirp)
569 					cp--;
570 				if (cp == ep->ex_dirp) {
571 					syslog(LOG_WARNING,
572 					      "Can't export %s", ep->ex_dirp);
573 					free_exp(ep);
574 					goto nextline;
575 				}
576 				savedc = *cp;
577 				*cp = '\0';
578 			}
579 			if (cp)
580 				*cp = savedc;
581 			ep->ex_rootuid = rootuid;
582 			ep->ex_exflags = exflags;
583 		} else {
584 			ep->ex_rootuid = fep->ex_rootuid;
585 			ep->ex_exflags = fep->ex_exflags;
586 		}
587 		ep->ex_dev = sb.st_dev;
588 		ep->ex_next = exphead.ex_next;
589 		ep->ex_prev = &exphead;
590 		if (ep->ex_next != NULL)
591 			ep->ex_next->ex_prev = ep;
592 		exphead.ex_next = ep;
593 nextline:
594 		;
595 	}
596 	fclose(inf);
597 	return;
598 err:
599 	syslog(LOG_ERR, "No more memory: mountd Failed");
600 	exit(2);
601 }
602 
603 /*
604  * Parse out the next white space separated field
605  */
606 nextfield(cp, endcp)
607 	char **cp;
608 	char **endcp;
609 {
610 	register char *p;
611 
612 	p = *cp;
613 	while (*p == ' ' || *p == '\t')
614 		p++;
615 	if (*p == '\n' || *p == '\0') {
616 		*cp = *endcp = p;
617 		return;
618 	}
619 	*cp = p++;
620 	while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
621 		p++;
622 	*endcp = p;
623 }
624 
625 /*
626  * Parse the option string
627  */
628 do_opt(cpopt, fep, ep, exflagsp, rootuidp)
629 	register char *cpopt;
630 	struct exportlist *fep, *ep;
631 	int *exflagsp, *rootuidp;
632 {
633 	register char *cpoptarg, *cpoptend;
634 
635 	while (cpopt && *cpopt) {
636 		if (cpoptend = index(cpopt, ','))
637 			*cpoptend++ = '\0';
638 		if (cpoptarg = index(cpopt, '='))
639 			*cpoptarg++ = '\0';
640 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
641 			if (fep && (fep->ex_exflags & MNT_EXRDONLY) == 0)
642 				syslog(LOG_WARNING, "ro failed for %s",
643 				       ep->ex_dirp);
644 			else
645 				*exflagsp |= MNT_EXRDONLY;
646 		} else if (!strcmp(cpopt, "root") || !strcmp(cpopt, "r")) {
647 			if (cpoptarg && isdigit(*cpoptarg)) {
648 				*rootuidp = atoi(cpoptarg);
649 				if (fep && fep->ex_rootuid != *rootuidp)
650 					syslog(LOG_WARNING,
651 					       "uid failed for %s",
652 					       ep->ex_dirp);
653 			} else
654 				syslog(LOG_WARNING,
655 				       "uid failed for %s",
656 				       ep->ex_dirp);
657 		} else
658 			syslog(LOG_WARNING, "opt %s ignored for %s", cpopt,
659 			       ep->ex_dirp);
660 		cpopt = cpoptend;
661 	}
662 }
663 
664 #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
665 /*
666  * Routines that maintain the remote mounttab
667  */
668 void get_mountlist()
669 {
670 	register struct mountlist *mlp, **mlpp;
671 	register char *eos, *dirp;
672 	int len;
673 	char str[STRSIZ];
674 	FILE *mlfile;
675 
676 	if (((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) &&
677 	    ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL)) {
678 		syslog(LOG_WARNING, "Can't open %s", _PATH_RMOUNTLIST);
679 		return;
680 	}
681 	mlpp = &mlhead;
682 	while (fgets(str, STRSIZ, mlfile) != NULL) {
683 		if ((dirp = index(str, '\t')) == NULL &&
684 		    (dirp = index(str, ' ')) == NULL)
685 			continue;
686 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
687 		len = dirp-str;
688 		if (len > RPCMNT_NAMELEN)
689 			len = RPCMNT_NAMELEN;
690 		bcopy(str, mlp->ml_host, len);
691 		mlp->ml_host[len] = '\0';
692 		while (*dirp == '\t' || *dirp == ' ')
693 			dirp++;
694 		if ((eos = index(dirp, '\t')) == NULL &&
695 		    (eos = index(dirp, ' ')) == NULL &&
696 		    (eos = index(dirp, '\n')) == NULL)
697 			len = strlen(dirp);
698 		else
699 			len = eos-dirp;
700 		if (len > RPCMNT_PATHLEN)
701 			len = RPCMNT_PATHLEN;
702 		bcopy(dirp, mlp->ml_dirp, len);
703 		mlp->ml_dirp[len] = '\0';
704 		mlp->ml_next = (struct mountlist *)0;
705 		*mlpp = mlp;
706 		mlpp = &mlp->ml_next;
707 	}
708 	fclose(mlfile);
709 }
710 
711 void del_mlist(hostp, dirp)
712 	register char *hostp, *dirp;
713 {
714 	register struct mountlist *mlp, **mlpp;
715 	FILE *mlfile;
716 	int fnd = 0;
717 
718 	mlpp = &mlhead;
719 	mlp = mlhead;
720 	while (mlp) {
721 		if (!strcmp(mlp->ml_host, hostp) &&
722 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
723 			fnd = 1;
724 			*mlpp = mlp->ml_next;
725 			free((caddr_t)mlp);
726 		}
727 		mlpp = &mlp->ml_next;
728 		mlp = mlp->ml_next;
729 	}
730 	if (fnd) {
731 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
732 			syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
733 			return;
734 		}
735 		mlp = mlhead;
736 		while (mlp) {
737 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
738 			mlp = mlp->ml_next;
739 		}
740 		fclose(mlfile);
741 	}
742 }
743 
744 void add_mlist(hostp, dirp)
745 	register char *hostp, *dirp;
746 {
747 	register struct mountlist *mlp, **mlpp;
748 	FILE *mlfile;
749 
750 	mlpp = &mlhead;
751 	mlp = mlhead;
752 	while (mlp) {
753 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
754 			return;
755 		mlpp = &mlp->ml_next;
756 		mlp = mlp->ml_next;
757 	}
758 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
759 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
760 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
761 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
762 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
763 	mlp->ml_next = (struct mountlist *)0;
764 	*mlpp = mlp;
765 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
766 		syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
767 		return;
768 	}
769 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
770 	fclose(mlfile);
771 }
772 
773 /*
774  * This function is called via. SIGTERM when the system is going down.
775  * It sends a broadcast RPCMNT_UMNTALL.
776  */
777 void
778 send_umntall()
779 {
780 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
781 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
782 	exit();
783 }
784 
785 umntall_each(resultsp, raddr)
786 	caddr_t resultsp;
787 	struct sockaddr_in *raddr;
788 {
789 	return (1);
790 }
791 
792 /*
793  * Free up an exports list component
794  */
795 free_exp(ep)
796 	register struct exportlist *ep;
797 {
798 	register struct grouplist *grp;
799 	register char **addrp;
800 	struct grouplist *grp2;
801 
802 	grp = ep->ex_groups;
803 	while (grp != NULL) {
804 		addrp = grp->gr_hp->h_addr_list;
805 		while (*addrp)
806 			free(*addrp++);
807 		free((caddr_t)grp->gr_hp->h_addr_list);
808 		free(grp->gr_hp->h_name);
809 		free((caddr_t)grp->gr_hp);
810 		grp2 = grp;
811 		grp = grp->gr_next;
812 		free((caddr_t)grp2);
813 	}
814 	free((caddr_t)ep);
815 }
816