4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
34 #include <sys/types.h>
36 #include <sys/param.h>
41 #include <rpcsvc/mount.h>
42 #include <sys/pathconf.h>
43 #include <sys/systeminfo.h>
44 #include <sys/utsname.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <sharefs/share.h>
54 #include "../lib/sharetab.h"
58 static char RMTAB
[] = "/etc/rmtab";
59 static FILE *rmtabf
= NULL
;
62 * There is nothing magic about the value selected here. Too low,
63 * and mountd might spend too much time rewriting the rmtab file.
64 * Too high, it won't do it frequently enough.
66 static int rmtab_del_thresh
= 250;
68 #define RMTAB_TOOMANY_DELETED() \
69 ((rmtab_deleted > rmtab_del_thresh) && (rmtab_deleted > rmtab_inuse))
72 * mountd's version of a "struct mountlist". It is the same except
73 * for the added ml_pos field.
81 static HASHSET mntlist
;
83 static int mntentry_equal(const void *, const void *);
84 static uint32_t mntentry_hash(const void *);
85 static int mntlist_contains(char *, char *);
86 static void rmtab_delete(long);
87 static long rmtab_insert(char *, char *);
88 static void rmtab_rewrite(void);
89 static void rmtab_parse(char *buf
);
90 static bool_t
xdr_mntlistencode(XDR
* xdrs
, HASHSET
* mntlist
);
93 strcpy(exmalloc(strlen(s)+1), s)
96 static int rmtab_inuse
;
97 static int rmtab_deleted
;
99 static rwlock_t rmtab_lock
; /* lock to protect rmtab list */
103 * Check whether the given client/path combination
104 * already appears in the mount list.
108 mntlist_contains(char *host
, char *path
)
115 return (h_get(mntlist
, &m
) != NULL
);
120 * Add an entry to the mount list.
121 * First check whether it's there already - the client
122 * may have crashed and be rebooting.
126 mntlist_insert(char *host
, char *path
)
128 if (!mntlist_contains(host
, path
)) {
131 m
= exmalloc(sizeof (struct mntentry
));
133 m
->m_host
= exstrdup(host
);
134 m
->m_path
= exstrdup(path
);
135 m
->m_pos
= rmtab_insert(host
, path
);
136 (void) h_put(mntlist
, m
);
141 mntlist_new(char *host
, char *path
)
143 (void) rw_wrlock(&rmtab_lock
);
144 mntlist_insert(host
, path
);
145 (void) rw_unlock(&rmtab_lock
);
149 * Delete an entry from the mount list.
153 mntlist_delete(char *host
, char *path
)
155 struct mntentry
*m
, mm
;
160 (void) rw_wrlock(&rmtab_lock
);
162 if ((m
= (struct mntentry
*)h_get(mntlist
, &mm
)) != NULL
) {
163 rmtab_delete(m
->m_pos
);
165 (void) h_delete(mntlist
, m
);
171 if (RMTAB_TOOMANY_DELETED())
174 (void) rw_unlock(&rmtab_lock
);
178 * Delete all entries for a host from the mount list
182 mntlist_delete_all(char *host
)
184 HASHSET_ITERATOR iterator
;
187 (void) rw_wrlock(&rmtab_lock
);
189 iterator
= h_iterator(mntlist
);
191 while ((m
= (struct mntentry
*)h_next(iterator
)) != NULL
) {
192 if (strcasecmp(m
->m_host
, host
))
195 rmtab_delete(m
->m_pos
);
197 (void) h_delete(mntlist
, m
);
204 if (RMTAB_TOOMANY_DELETED())
207 (void) rw_unlock(&rmtab_lock
);
209 if (iterator
!= NULL
)
214 * Equivalent to xdr_mountlist from librpcsvc but for HASHSET
215 * rather that for a linked list. It is used only to encode data
216 * from HASHSET before sending it over the wire.
220 xdr_mntlistencode(XDR
*xdrs
, HASHSET
*mntlist
)
222 HASHSET_ITERATOR iterator
= h_iterator(*mntlist
);
225 struct mntentry
*m
= (struct mntentry
*)h_next(iterator
);
226 bool_t more_data
= (m
!= NULL
);
228 if (!xdr_bool(xdrs
, &more_data
)) {
229 if (iterator
!= NULL
)
237 if ((!xdr_name(xdrs
, &m
->m_host
)) ||
238 (!xdr_dirpath(xdrs
, &m
->m_path
))) {
239 if (iterator
!= NULL
)
246 if (iterator
!= NULL
)
253 mntlist_send(SVCXPRT
*transp
)
255 (void) rw_rdlock(&rmtab_lock
);
258 if (!svc_sendreply(transp
, xdr_mntlistencode
, (char *)&mntlist
))
259 log_cant_reply(transp
);
261 (void) rw_unlock(&rmtab_lock
);
265 * Compute a 32 bit hash value for an mntlist entry.
269 * The string hashing algorithm is from the "Dragon Book" --
270 * "Compilers: Principles, Tools & Techniques", by Aho, Sethi, Ullman
272 * And is modified for this application from usr/src/uts/common/os/modhash.c
276 mntentry_str_hash(char *s
, uint_t hash
)
280 for (; *s
!= '\0'; s
++) {
281 hash
= (hash
<< 4) + *s
;
282 if ((g
= (hash
& 0xf0000000)) != 0) {
292 mntentry_hash(const void *p
)
294 struct mntentry
*m
= (struct mntentry
*)p
;
297 hash
= mntentry_str_hash(m
->m_host
, 0);
298 hash
= mntentry_str_hash(m
->m_path
, hash
);
304 * Compare mntlist entries.
305 * The comparison ignores a value of m_pos.
309 mntentry_equal(const void *p1
, const void *p2
)
311 struct mntentry
*m1
= (struct mntentry
*)p1
;
312 struct mntentry
*m2
= (struct mntentry
*)p2
;
314 return ((strcasecmp(m1
->m_host
, m2
->m_host
) ||
315 strcmp(m1
->m_path
, m2
->m_path
)) ? 0 : 1);
319 * Rewrite /etc/rmtab with a current content of mntlist.
325 (void) fclose(rmtabf
);
327 /* Rewrite the file. */
328 if ((rmtabf
= fopen(RMTAB
, "w+")) != NULL
) {
329 HASHSET_ITERATOR iterator
;
332 (void) fchmod(fileno(rmtabf
),
333 (S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
));
334 rmtab_inuse
= rmtab_deleted
= 0;
336 iterator
= h_iterator(mntlist
);
338 while ((m
= (struct mntentry
*)h_next(iterator
)) != NULL
)
339 m
->m_pos
= rmtab_insert(m
->m_host
, m
->m_path
);
340 if (iterator
!= NULL
)
346 * Parse the content of /etc/rmtab and insert the entries into mntlist.
347 * The buffer s should be ended with a NUL char.
356 struct in6_addr ipv6addr
;
373 tmp
= strchr(s
, ']');
376 if (inet_pton(AF_INET6
, s
, &ipv6addr
) > 0) {
394 mntlist_insert(host
, path
);
398 mntlist_insert(host
, path
);
419 * Read in contents of rmtab.
420 * Call rmtab_parse to parse the file and store entries in mntlist.
421 * Rewrites the file to get rid of unused entries.
424 #define RMTAB_LOADLEN (16*2024) /* Max bytes to read at a time */
431 (void) rwlock_init(&rmtab_lock
, USYNC_THREAD
, NULL
);
434 * Don't need to lock the list at this point
435 * because there's only a single thread running.
437 mntlist
= h_create(mntentry_hash
, mntentry_equal
, 101, 0.75);
439 if ((fp
= fopen(RMTAB
, "r")) != NULL
) {
440 char buf
[RMTAB_LOADLEN
+1];
444 * Read at most RMTAB_LOADLEN bytes from /etc/rmtab.
445 * - if fread returns RMTAB_LOADLEN we can be in the middle
446 * of a line so change the last newline character into NUL
447 * and seek back to the next character after newline.
448 * - otherwise set NUL behind the last character read.
450 while ((len
= fread(buf
, 1, RMTAB_LOADLEN
, fp
)) > 0) {
451 if (len
== RMTAB_LOADLEN
) {
454 for (i
= 1; i
< len
; i
++) {
455 if (buf
[len
-i
] == '\n') {
457 (void) fseek(fp
, -i
+ 1,
464 /* Put a NUL character at the end of buffer */
475 * Write an entry at the current location in rmtab
476 * for the given client and path.
478 * Returns the starting position of the entry
479 * or -1 if there was an error.
483 rmtab_insert(char *host
, char *path
)
486 struct in6_addr ipv6addr
;
488 if (rmtabf
== NULL
|| fseek(rmtabf
, 0L, 2) == -1) {
494 * Check if host is an IPv6 literal
497 if (inet_pton(AF_INET6
, host
, &ipv6addr
) > 0) {
498 if (fprintf(rmtabf
, "[%s]:%s\n", host
, path
) == EOF
) {
502 if (fprintf(rmtabf
, "%s:%s\n", host
, path
) == EOF
) {
506 if (fflush(rmtabf
) == EOF
) {
514 * Mark as unused the rmtab entry at the given offset in the file.
518 rmtab_delete(long pos
)
520 if (rmtabf
!= NULL
&& pos
!= -1 && fseek(rmtabf
, pos
, 0) == 0) {
521 (void) fprintf(rmtabf
, "#");
522 (void) fflush(rmtabf
);