xref: /titanic_52/usr/src/cmd/fs.d/nfs/mountd/rmtab.c (revision 54d34259930c76758a7e9e03732cb1e37f9a6ba9)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5a237e38eSth199096  * Common Development and Distribution License (the "License").
6a237e38eSth199096  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21a237e38eSth199096 
227c478bd9Sstevel@tonic-gate /*
23*54d34259SMarcel Telka  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
24*54d34259SMarcel Telka  */
25*54d34259SMarcel Telka 
26*54d34259SMarcel Telka /*
274a508a79SThomas Haynes  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
287c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <ctype.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <sys/param.h>
377c478bd9Sstevel@tonic-gate #include <sys/stat.h>
387c478bd9Sstevel@tonic-gate #include <sys/file.h>
397c478bd9Sstevel@tonic-gate #include <sys/time.h>
407c478bd9Sstevel@tonic-gate #include <errno.h>
417c478bd9Sstevel@tonic-gate #include <rpcsvc/mount.h>
427c478bd9Sstevel@tonic-gate #include <sys/pathconf.h>
437c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
447c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
457c478bd9Sstevel@tonic-gate #include <signal.h>
467c478bd9Sstevel@tonic-gate #include <locale.h>
477c478bd9Sstevel@tonic-gate #include <unistd.h>
487c478bd9Sstevel@tonic-gate #include <thread.h>
497c478bd9Sstevel@tonic-gate #include <syslog.h>
507c478bd9Sstevel@tonic-gate #include <sys/socket.h>
517c478bd9Sstevel@tonic-gate #include <netinet/in.h>
527c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
53a237e38eSth199096 #include <sharefs/share.h>
547c478bd9Sstevel@tonic-gate #include "../lib/sharetab.h"
557c478bd9Sstevel@tonic-gate #include "hashset.h"
567c478bd9Sstevel@tonic-gate #include "mountd.h"
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate static char RMTAB[] = "/etc/rmtab";
597c478bd9Sstevel@tonic-gate static FILE *rmtabf = NULL;
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * There is nothing magic about the value selected here. Too low,
637c478bd9Sstevel@tonic-gate  * and mountd might spend too much time rewriting the rmtab file.
647c478bd9Sstevel@tonic-gate  * Too high, it won't do it frequently enough.
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate static int rmtab_del_thresh = 250;
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #define	RMTAB_TOOMANY_DELETED()	\
697c478bd9Sstevel@tonic-gate 	((rmtab_deleted > rmtab_del_thresh) && (rmtab_deleted > rmtab_inuse))
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate  * mountd's version of a "struct mountlist". It is the same except
737c478bd9Sstevel@tonic-gate  * for the added ml_pos field.
747c478bd9Sstevel@tonic-gate  */
757c478bd9Sstevel@tonic-gate struct mntentry {
767c478bd9Sstevel@tonic-gate 	char  *m_host;
777c478bd9Sstevel@tonic-gate 	char  *m_path;
787c478bd9Sstevel@tonic-gate 	long   m_pos;
797c478bd9Sstevel@tonic-gate };
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static HASHSET mntlist;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate static int mntentry_equal(const void *, const void *);
847c478bd9Sstevel@tonic-gate static uint32_t mntentry_hash(const void *);
857c478bd9Sstevel@tonic-gate static int mntlist_contains(char *, char *);
867c478bd9Sstevel@tonic-gate static void rmtab_delete(long);
877c478bd9Sstevel@tonic-gate static long rmtab_insert(char *, char *);
887c478bd9Sstevel@tonic-gate static void rmtab_rewrite(void);
897c478bd9Sstevel@tonic-gate static void rmtab_parse(char *buf);
907c478bd9Sstevel@tonic-gate static bool_t xdr_mntlistencode(XDR * xdrs, HASHSET * mntlist);
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate #define	exstrdup(s) \
937c478bd9Sstevel@tonic-gate 	strcpy(exmalloc(strlen(s)+1), s)
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate static int rmtab_inuse;
977c478bd9Sstevel@tonic-gate static int rmtab_deleted;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate static rwlock_t rmtab_lock;	/* lock to protect rmtab list */
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate  * Check whether the given client/path combination
1047c478bd9Sstevel@tonic-gate  * already appears in the mount list.
1057c478bd9Sstevel@tonic-gate  */
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate static int
1087c478bd9Sstevel@tonic-gate mntlist_contains(char *host, char *path)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate 	struct mntentry m;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	m.m_host = host;
1137c478bd9Sstevel@tonic-gate 	m.m_path = path;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	return (h_get(mntlist, &m) != NULL);
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /*
1207c478bd9Sstevel@tonic-gate  *  Add an entry to the mount list.
1217c478bd9Sstevel@tonic-gate  *  First check whether it's there already - the client
1227c478bd9Sstevel@tonic-gate  *  may have crashed and be rebooting.
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate static void
1267c478bd9Sstevel@tonic-gate mntlist_insert(char *host, char *path)
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	if (!mntlist_contains(host, path)) {
1297c478bd9Sstevel@tonic-gate 		struct mntentry *m;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 		m = exmalloc(sizeof (struct mntentry));
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 		m->m_host = exstrdup(host);
1347c478bd9Sstevel@tonic-gate 		m->m_path = exstrdup(path);
1357c478bd9Sstevel@tonic-gate 		m->m_pos = rmtab_insert(host, path);
1367c478bd9Sstevel@tonic-gate 		(void) h_put(mntlist, m);
1377c478bd9Sstevel@tonic-gate 	}
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate void
1417c478bd9Sstevel@tonic-gate mntlist_new(char *host, char *path)
1427c478bd9Sstevel@tonic-gate {
1437c478bd9Sstevel@tonic-gate 	(void) rw_wrlock(&rmtab_lock);
1447c478bd9Sstevel@tonic-gate 	mntlist_insert(host, path);
1457c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&rmtab_lock);
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * Delete an entry from the mount list.
1507c478bd9Sstevel@tonic-gate  */
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate void
1537c478bd9Sstevel@tonic-gate mntlist_delete(char *host, char *path)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate 	struct mntentry *m, mm;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	mm.m_host = host;
1587c478bd9Sstevel@tonic-gate 	mm.m_path = path;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	(void) rw_wrlock(&rmtab_lock);
1617c478bd9Sstevel@tonic-gate 
162*54d34259SMarcel Telka 	if ((m = (struct mntentry *)h_get(mntlist, &mm)) != NULL) {
1637c478bd9Sstevel@tonic-gate 		rmtab_delete(m->m_pos);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 		(void) h_delete(mntlist, m);
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 		free(m->m_path);
1687c478bd9Sstevel@tonic-gate 		free(m->m_host);
1697c478bd9Sstevel@tonic-gate 		free(m);
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 		if (RMTAB_TOOMANY_DELETED())
1727c478bd9Sstevel@tonic-gate 			rmtab_rewrite();
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&rmtab_lock);
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate /*
1787c478bd9Sstevel@tonic-gate  * Delete all entries for a host from the mount list
1797c478bd9Sstevel@tonic-gate  */
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate void
1827c478bd9Sstevel@tonic-gate mntlist_delete_all(char *host)
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate 	HASHSET_ITERATOR iterator;
1857c478bd9Sstevel@tonic-gate 	struct mntentry *m;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	(void) rw_wrlock(&rmtab_lock);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	iterator = h_iterator(mntlist);
1907c478bd9Sstevel@tonic-gate 
191*54d34259SMarcel Telka 	while ((m = (struct mntentry *)h_next(iterator)) != NULL) {
1927c478bd9Sstevel@tonic-gate 		if (strcasecmp(m->m_host, host))
1937c478bd9Sstevel@tonic-gate 			continue;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 		rmtab_delete(m->m_pos);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 		(void) h_delete(mntlist, m);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 		free(m->m_path);
2007c478bd9Sstevel@tonic-gate 		free(m->m_host);
2017c478bd9Sstevel@tonic-gate 		free(m);
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	if (RMTAB_TOOMANY_DELETED())
2057c478bd9Sstevel@tonic-gate 		rmtab_rewrite();
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&rmtab_lock);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	if (iterator != NULL)
2107c478bd9Sstevel@tonic-gate 		free(iterator);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate /*
2147c478bd9Sstevel@tonic-gate  * Equivalent to xdr_mountlist from librpcsvc but for HASHSET
2157c478bd9Sstevel@tonic-gate  * rather that for a linked list. It is used only to encode data
2167c478bd9Sstevel@tonic-gate  * from HASHSET before sending it over the wire.
2177c478bd9Sstevel@tonic-gate  */
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate static bool_t
2207c478bd9Sstevel@tonic-gate xdr_mntlistencode(XDR *xdrs, HASHSET *mntlist)
2217c478bd9Sstevel@tonic-gate {
2227c478bd9Sstevel@tonic-gate 	HASHSET_ITERATOR iterator = h_iterator(*mntlist);
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	for (;;) {
2257c478bd9Sstevel@tonic-gate 		struct mntentry *m = (struct mntentry *)h_next(iterator);
2267c478bd9Sstevel@tonic-gate 		bool_t more_data = (m != NULL);
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 		if (!xdr_bool(xdrs, &more_data)) {
2297c478bd9Sstevel@tonic-gate 			if (iterator != NULL)
2307c478bd9Sstevel@tonic-gate 				free(iterator);
2317c478bd9Sstevel@tonic-gate 			return (FALSE);
2327c478bd9Sstevel@tonic-gate 		}
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 		if (!more_data)
2357c478bd9Sstevel@tonic-gate 			break;
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 		if ((!xdr_name(xdrs, &m->m_host)) ||
2387c478bd9Sstevel@tonic-gate 		    (!xdr_dirpath(xdrs, &m->m_path))) {
2397c478bd9Sstevel@tonic-gate 			if (iterator != NULL)
2407c478bd9Sstevel@tonic-gate 				free(iterator);
2417c478bd9Sstevel@tonic-gate 			return (FALSE);
2427c478bd9Sstevel@tonic-gate 		}
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	}
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	if (iterator != NULL)
2477c478bd9Sstevel@tonic-gate 		free(iterator);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	return (TRUE);
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate void
2537c478bd9Sstevel@tonic-gate mntlist_send(SVCXPRT *transp)
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate 	(void) rw_rdlock(&rmtab_lock);
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	errno = 0;
2587c478bd9Sstevel@tonic-gate 	if (!svc_sendreply(transp, xdr_mntlistencode, (char *)&mntlist))
2597c478bd9Sstevel@tonic-gate 		log_cant_reply(transp);
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&rmtab_lock);
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate /*
2654a508a79SThomas Haynes  * Compute a 32 bit hash value for an mntlist entry.
2667c478bd9Sstevel@tonic-gate  */
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate /*
2694a508a79SThomas Haynes  * The string hashing algorithm is from the "Dragon Book" --
2704a508a79SThomas Haynes  * "Compilers: Principles, Tools & Techniques", by Aho, Sethi, Ullman
2714a508a79SThomas Haynes  *
2724a508a79SThomas Haynes  * And is modified for this application from usr/src/uts/common/os/modhash.c
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate 
2754a508a79SThomas Haynes static uint_t
2764a508a79SThomas Haynes mntentry_str_hash(char *s, uint_t hash)
2774a508a79SThomas Haynes {
2784a508a79SThomas Haynes 	uint_t	g;
2794a508a79SThomas Haynes 
2804a508a79SThomas Haynes 	for (; *s != '\0'; s++) {
2814a508a79SThomas Haynes 		hash = (hash << 4) + *s;
2824a508a79SThomas Haynes 		if ((g = (hash & 0xf0000000)) != 0) {
2834a508a79SThomas Haynes 			hash ^= (g >> 24);
2844a508a79SThomas Haynes 			hash ^= g;
2854a508a79SThomas Haynes 		}
2864a508a79SThomas Haynes 	}
2874a508a79SThomas Haynes 
2884a508a79SThomas Haynes 	return (hash);
2894a508a79SThomas Haynes }
2904a508a79SThomas Haynes 
2917c478bd9Sstevel@tonic-gate static uint32_t
2927c478bd9Sstevel@tonic-gate mntentry_hash(const void *p)
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate 	struct mntentry *m = (struct mntentry *)p;
2954a508a79SThomas Haynes 	uint_t hash;
2967c478bd9Sstevel@tonic-gate 
2974a508a79SThomas Haynes 	hash = mntentry_str_hash(m->m_host, 0);
2984a508a79SThomas Haynes 	hash = mntentry_str_hash(m->m_path, hash);
2997c478bd9Sstevel@tonic-gate 
3004a508a79SThomas Haynes 	return (hash);
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate /*
3047c478bd9Sstevel@tonic-gate  * Compare mntlist entries.
3057c478bd9Sstevel@tonic-gate  * The comparison ignores a value of m_pos.
3067c478bd9Sstevel@tonic-gate  */
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate static int
3097c478bd9Sstevel@tonic-gate mntentry_equal(const void *p1, const void *p2)
3107c478bd9Sstevel@tonic-gate {
3117c478bd9Sstevel@tonic-gate 	struct mntentry *m1 = (struct mntentry *)p1;
3127c478bd9Sstevel@tonic-gate 	struct mntentry *m2 = (struct mntentry *)p2;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	return ((strcasecmp(m1->m_host, m2->m_host) ||
3157c478bd9Sstevel@tonic-gate 	    strcmp(m1->m_path, m2->m_path)) ? 0 : 1);
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate /*
3197c478bd9Sstevel@tonic-gate  * Rewrite /etc/rmtab with a current content of mntlist.
3207c478bd9Sstevel@tonic-gate  */
3217c478bd9Sstevel@tonic-gate static void
3227c478bd9Sstevel@tonic-gate rmtab_rewrite()
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate 	if (rmtabf)
3257c478bd9Sstevel@tonic-gate 		(void) fclose(rmtabf);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	/* Rewrite the file. */
328*54d34259SMarcel Telka 	if ((rmtabf = fopen(RMTAB, "w+")) != NULL) {
3297c478bd9Sstevel@tonic-gate 		HASHSET_ITERATOR iterator;
3307c478bd9Sstevel@tonic-gate 		struct mntentry *m;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 		(void) fchmod(fileno(rmtabf),
3337c478bd9Sstevel@tonic-gate 		    (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH));
3347c478bd9Sstevel@tonic-gate 		rmtab_inuse = rmtab_deleted = 0;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 		iterator = h_iterator(mntlist);
3377c478bd9Sstevel@tonic-gate 
338*54d34259SMarcel Telka 		while ((m = (struct mntentry *)h_next(iterator)) != NULL)
3397c478bd9Sstevel@tonic-gate 			m->m_pos = rmtab_insert(m->m_host, m->m_path);
3407c478bd9Sstevel@tonic-gate 		if (iterator != NULL)
3417c478bd9Sstevel@tonic-gate 			free(iterator);
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate  * Parse the content of /etc/rmtab and insert the entries into mntlist.
3477c478bd9Sstevel@tonic-gate  * The buffer s should be ended with a NUL char.
3487c478bd9Sstevel@tonic-gate  */
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate static void
3517c478bd9Sstevel@tonic-gate rmtab_parse(char *s)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate 	char  *host;
3547c478bd9Sstevel@tonic-gate 	char  *path;
3557c478bd9Sstevel@tonic-gate 	char  *tmp;
3567c478bd9Sstevel@tonic-gate 	struct in6_addr ipv6addr;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate host_part:
3597c478bd9Sstevel@tonic-gate 	if (*s == '#')
3607c478bd9Sstevel@tonic-gate 		goto skip_rest;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	host = s;
3637c478bd9Sstevel@tonic-gate 	for (;;) {
3647c478bd9Sstevel@tonic-gate 		switch (*s++) {
3657c478bd9Sstevel@tonic-gate 		case '\0':
3667c478bd9Sstevel@tonic-gate 			return;
3677c478bd9Sstevel@tonic-gate 		case '\n':
3687c478bd9Sstevel@tonic-gate 			goto host_part;
3697c478bd9Sstevel@tonic-gate 		case ':':
3707c478bd9Sstevel@tonic-gate 			s[-1] = '\0';
3717c478bd9Sstevel@tonic-gate 			goto path_part;
3727c478bd9Sstevel@tonic-gate 		case '[':
3737c478bd9Sstevel@tonic-gate 			tmp = strchr(s, ']');
3747c478bd9Sstevel@tonic-gate 			if (tmp) {
3757c478bd9Sstevel@tonic-gate 				*tmp = '\0';
3767c478bd9Sstevel@tonic-gate 				if (inet_pton(AF_INET6, s, &ipv6addr) > 0) {
3777c478bd9Sstevel@tonic-gate 					host = s;
3787c478bd9Sstevel@tonic-gate 					s = ++tmp;
3797c478bd9Sstevel@tonic-gate 				} else
3807c478bd9Sstevel@tonic-gate 					*tmp = ']';
3817c478bd9Sstevel@tonic-gate 			}
3827c478bd9Sstevel@tonic-gate 		default:
3837c478bd9Sstevel@tonic-gate 			continue;
3847c478bd9Sstevel@tonic-gate 		}
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate path_part:
3887c478bd9Sstevel@tonic-gate 	path = s;
3897c478bd9Sstevel@tonic-gate 	for (;;) {
3907c478bd9Sstevel@tonic-gate 		switch (*s++) {
3917c478bd9Sstevel@tonic-gate 		case '\n':
3927c478bd9Sstevel@tonic-gate 			s[-1] = '\0';
3937c478bd9Sstevel@tonic-gate 			if (*host && *path)
3947c478bd9Sstevel@tonic-gate 				mntlist_insert(host, path);
3957c478bd9Sstevel@tonic-gate 			goto host_part;
3967c478bd9Sstevel@tonic-gate 		case '\0':
3977c478bd9Sstevel@tonic-gate 			if (*host && *path)
3987c478bd9Sstevel@tonic-gate 				mntlist_insert(host, path);
3997c478bd9Sstevel@tonic-gate 			return;
4007c478bd9Sstevel@tonic-gate 		default:
4017c478bd9Sstevel@tonic-gate 			continue;
4027c478bd9Sstevel@tonic-gate 		}
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate skip_rest:
4067c478bd9Sstevel@tonic-gate 	for (;;) {
4077c478bd9Sstevel@tonic-gate 		switch (*++s) {
4087c478bd9Sstevel@tonic-gate 		case '\n':
4097c478bd9Sstevel@tonic-gate 			goto host_part;
4107c478bd9Sstevel@tonic-gate 		case '\0':
4117c478bd9Sstevel@tonic-gate 			return;
4127c478bd9Sstevel@tonic-gate 		default:
4137c478bd9Sstevel@tonic-gate 			continue;
4147c478bd9Sstevel@tonic-gate 		}
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate /*
4197c478bd9Sstevel@tonic-gate  * Read in contents of rmtab.
4207c478bd9Sstevel@tonic-gate  * Call rmtab_parse to parse the file and store entries in mntlist.
4217c478bd9Sstevel@tonic-gate  * Rewrites the file to get rid of unused entries.
4227c478bd9Sstevel@tonic-gate  */
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate #define	RMTAB_LOADLEN	(16*2024)	/* Max bytes to read at a time */
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate void
4277c478bd9Sstevel@tonic-gate rmtab_load()
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate 	FILE *fp;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	(void) rwlock_init(&rmtab_lock, USYNC_THREAD, NULL);
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	/*
4347c478bd9Sstevel@tonic-gate 	 * Don't need to lock the list at this point
4357c478bd9Sstevel@tonic-gate 	 * because there's only a single thread running.
4367c478bd9Sstevel@tonic-gate 	 */
4377c478bd9Sstevel@tonic-gate 	mntlist = h_create(mntentry_hash, mntentry_equal, 101, 0.75);
4387c478bd9Sstevel@tonic-gate 
439*54d34259SMarcel Telka 	if ((fp = fopen(RMTAB, "r")) != NULL) {
4407c478bd9Sstevel@tonic-gate 		char buf[RMTAB_LOADLEN+1];
4417c478bd9Sstevel@tonic-gate 		size_t len;
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 		/*
4447c478bd9Sstevel@tonic-gate 		 * Read at most RMTAB_LOADLEN bytes from /etc/rmtab.
4457c478bd9Sstevel@tonic-gate 		 * - if fread returns RMTAB_LOADLEN we can be in the middle
4467c478bd9Sstevel@tonic-gate 		 *   of a line so change the last newline character into NUL
4477c478bd9Sstevel@tonic-gate 		 *   and seek back to the next character after newline.
4487c478bd9Sstevel@tonic-gate 		 * - otherwise set NUL behind the last character read.
4497c478bd9Sstevel@tonic-gate 		 */
4507c478bd9Sstevel@tonic-gate 		while ((len = fread(buf, 1, RMTAB_LOADLEN, fp)) > 0) {
4517c478bd9Sstevel@tonic-gate 			if (len == RMTAB_LOADLEN) {
4527c478bd9Sstevel@tonic-gate 				int i;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 				for (i = 1; i < len; i++) {
4557c478bd9Sstevel@tonic-gate 					if (buf[len-i] == '\n') {
4567c478bd9Sstevel@tonic-gate 						buf[len-i] = '\0';
4577c478bd9Sstevel@tonic-gate 						(void) fseek(fp, -i + 1,
4587c478bd9Sstevel@tonic-gate 						    SEEK_CUR);
4597c478bd9Sstevel@tonic-gate 						goto parse;
4607c478bd9Sstevel@tonic-gate 					}
4617c478bd9Sstevel@tonic-gate 				}
4627c478bd9Sstevel@tonic-gate 			}
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 			/* Put a NUL character at the end of buffer */
4657c478bd9Sstevel@tonic-gate 			buf[len] = '\0';
4667c478bd9Sstevel@tonic-gate 	parse:
4677c478bd9Sstevel@tonic-gate 			rmtab_parse(buf);
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 	rmtab_rewrite();
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate /*
4757c478bd9Sstevel@tonic-gate  * Write an entry at the current location in rmtab
4767c478bd9Sstevel@tonic-gate  * for the given client and path.
4777c478bd9Sstevel@tonic-gate  *
4787c478bd9Sstevel@tonic-gate  * Returns the starting position of the entry
4797c478bd9Sstevel@tonic-gate  * or -1 if there was an error.
4807c478bd9Sstevel@tonic-gate  */
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate long
4837c478bd9Sstevel@tonic-gate rmtab_insert(char *host, char *path)
4847c478bd9Sstevel@tonic-gate {
4857c478bd9Sstevel@tonic-gate 	long   pos;
4867c478bd9Sstevel@tonic-gate 	struct in6_addr ipv6addr;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	if (rmtabf == NULL || fseek(rmtabf, 0L, 2) == -1) {
4897c478bd9Sstevel@tonic-gate 		return (-1);
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate 	pos = ftell(rmtabf);
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	/*
4947c478bd9Sstevel@tonic-gate 	 * Check if host is an IPv6 literal
4957c478bd9Sstevel@tonic-gate 	 */
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	if (inet_pton(AF_INET6, host, &ipv6addr) > 0) {
4987c478bd9Sstevel@tonic-gate 		if (fprintf(rmtabf, "[%s]:%s\n", host, path) == EOF) {
4997c478bd9Sstevel@tonic-gate 			return (-1);
5007c478bd9Sstevel@tonic-gate 		}
5017c478bd9Sstevel@tonic-gate 	} else {
5027c478bd9Sstevel@tonic-gate 		if (fprintf(rmtabf, "%s:%s\n", host, path) == EOF) {
5037c478bd9Sstevel@tonic-gate 			return (-1);
5047c478bd9Sstevel@tonic-gate 		}
5057c478bd9Sstevel@tonic-gate 	}
5067c478bd9Sstevel@tonic-gate 	if (fflush(rmtabf) == EOF) {
5077c478bd9Sstevel@tonic-gate 		return (-1);
5087c478bd9Sstevel@tonic-gate 	}
5097c478bd9Sstevel@tonic-gate 	rmtab_inuse++;
5107c478bd9Sstevel@tonic-gate 	return (pos);
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate /*
5147c478bd9Sstevel@tonic-gate  * Mark as unused the rmtab entry at the given offset in the file.
5157c478bd9Sstevel@tonic-gate  */
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate void
5187c478bd9Sstevel@tonic-gate rmtab_delete(long pos)
5197c478bd9Sstevel@tonic-gate {
5207c478bd9Sstevel@tonic-gate 	if (rmtabf != NULL && pos != -1 && fseek(rmtabf, pos, 0) == 0) {
5217c478bd9Sstevel@tonic-gate 		(void) fprintf(rmtabf, "#");
5227c478bd9Sstevel@tonic-gate 		(void) fflush(rmtabf);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 		rmtab_inuse--;
5257c478bd9Sstevel@tonic-gate 		rmtab_deleted++;
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate }
528