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