1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Portions Copyright 2007-2011 Apple Inc.
29 */
30
31#include <stdio.h>
32#include <string.h>
33#include <ctype.h>
34#include <unistd.h>
35#include <stdlib.h>
36#include <sys/param.h>
37#include <pthread.h>
38#include <fstab.h>
39#include <errno.h>
40#include <assert.h>
41#include <mntopts.h>
42#include "autofs.h"
43#include "automount.h"
44#include "auto_mntopts.h"
45
46#define MIN_CACHE_TIME	30	// min cache time for fstab cache (sec)
47
48/*
49 * Structure for a server host in fstab.
50 */
51struct fstabhost {
52	char	*name;			/* name of the host */
53	struct fstabnode *fstab_ents;	/* fstab entries for that host */
54	struct fstabhost *next;		/* next entry in hash table bucket */
55};
56
57#define HASHTABLESIZE	251
58
59/*
60 * Hash table of hosts with at least one "net" entry.
61 */
62static struct fstabhost *fstab_hashtable[HASHTABLESIZE];
63
64/*
65 * Hash table of static map entries.
66 */
67static struct staticmap *static_hashtable[HASHTABLESIZE];
68
69/*
70 * Read/write lock on the cache.
71 */
72static pthread_rwlock_t fstab_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
73
74static time_t min_cachetime;	// Min time that the cache is valid
75static time_t max_cachetime;	// Max time that the cache is valid
76
77static int
78process_fstab_mntopts(struct fstab *fs, char **mntops_outp, char **url)
79{
80	char *mntops_out;
81	char *mntops_copy;
82	size_t optlen;
83	char *p, *pp;
84	char *optp;
85        int error = 0;
86
87	/*
88	 * Remove "net", "bg", and "fg" from the mount options;
89	 * "net" is irrelevant, and the automounter can't mount
90	 * stuff in the background - it's not supposed to return
91	 * until the mount has succeeded or failed - so "bg"
92	 * should be ignored and "fg" is irrelevant.
93	 *
94	 * If "url==" appears, extract the URL and return it through
95	 * "*url", and remove it from the mount options.
96	 *
97	 * If "fs->fs_type" isn't a null string, it's either "rw" or "ro";
98	 * add it to the end of the list of options.
99	 */
100	optlen = strlen(fs->fs_mntops) + strlen(fs->fs_type) + 1 + 1;
101	if (optlen > MAXOPTSLEN)
102		return (ENAMETOOLONG);
103	mntops_out = (char *)malloc(optlen);
104	if (mntops_out == NULL)
105		return (ENOMEM);
106	strcpy(mntops_out, "");
107
108	/*
109	 * Copy over mount options, except for "net", "bg", "fg",
110	 * "browse", "nobrowse", or "url==".  We discard "net",
111	 * "bg", and "fg"; we map "browse" and "nobrowse" to
112	 * "findervol" and "nofindervol"; we extract the URL from
113	 * "url==" and return it through "*url".
114	 */
115	*url = NULL;	/* haven't seen it yet */
116
117	/*
118	 * Copy option string, since it is about to be torn asunder ...
119	 */
120	if ((mntops_copy = strdup(fs->fs_mntops)) == NULL) {
121		free(mntops_out);
122		return (ENOMEM);
123	}
124	pp = mntops_copy;
125
126	while ((p = strsep(&pp, ",")) != NULL) {
127		if (strcmp(p, "net") == 0 || strcmp(p, "bg") == 0 ||
128		    strcmp(p, "bg") == 0)
129			continue;
130
131		if (strncmp(p, "url==", 5) == 0) {
132			/*
133			 * Extract the URL.
134			 */
135			if (*url != NULL)
136				free(*url);
137			*url = strdup(p + 5);
138			if (*url == NULL) {
139				free(mntops_out);
140				free(mntops_copy);
141				return (ENOMEM);
142			}
143			continue;	/* don't add it to the mount options */
144		}
145
146		if (strcmp(p, "browse") == 0)
147			optp = "findervol";
148		else if (strcmp(p, "nobrowse") == 0)
149			optp = "nofindervol";
150		else
151			optp = p;
152		if (mntops_out[0] != '\0') {
153			/*
154			 * We already have mount options; add
155			 * a comma before this one.
156			 */
157			if ((error = CHECK_STRCAT(mntops_out, ",", optlen))) {
158                                error = ENAMETOOLONG;
159                                goto DONE;
160                        }
161		}
162                if ((error = CHECK_STRCAT(mntops_out, optp, optlen))) {
163                        error = ENAMETOOLONG;
164                        goto DONE;
165                }
166	}
167	if (fs->fs_type[0] != '\0') {
168		/*
169		 * We have a type, which is either "rw", "ro", or nothing.
170		 * If it's "rw" or "ro", add that to the end of the
171		 * options list, just as the old automounter did.
172		 */
173		if (mntops_out[0] != '\0') {
174			/*
175			 * We already have mount options; add
176			 * a comma before this one.
177			 */
178                        if ((error = CHECK_STRCAT(mntops_out, ",", optlen))) {
179                                error = ENAMETOOLONG;
180                                goto DONE;
181                        }
182		}
183                if ((error = CHECK_STRCAT(mntops_out, fs->fs_type, optlen))) {
184                        error = ENAMETOOLONG;
185                        goto DONE;
186                }
187	}
188DONE:
189	*mntops_outp = mntops_out;
190	free(mntops_copy);
191	return error;
192}
193
194static void
195freefst_ent(fst)
196	struct fstabnode *fst;
197{
198	if (fst->fst_dir != NULL)
199		free(fst->fst_dir);
200	if (fst->fst_vfstype != NULL)
201		free(fst->fst_vfstype);
202	if (fst->fst_mntops != NULL)
203		free(fst->fst_mntops);
204	if (fst->fst_url != NULL)
205		free(fst->fst_url);
206	free((char *)fst);
207}
208
209static void
210freefst_list(fst)
211	struct fstabnode *fst;
212{
213	struct fstabnode *tmpfst;
214
215	while (fst) {
216		tmpfst = fst->fst_next;
217		freefst_ent(fst);
218		fst = tmpfst;
219	}
220}
221
222static struct fstabhost *
223find_host_entry(const char *host, struct fstabhost ***bucketp)
224{
225	size_t hash;
226	const unsigned char *hashp;
227	unsigned char c;
228	struct fstabhost **bucket;
229	struct fstabhost *hostent;
230
231	/*
232	 * Cheesy hash function - just add all the characters in the
233	 * host name together, after lower-casing all upper-case
234	 * letters, and take it mod HASHTABLESIZE.
235	 */
236	hash = 0;
237	for (hashp = (const unsigned char *)host; (c = *hashp) != '\0'; hashp++)
238		hash += tolower(c);
239	bucket = &fstab_hashtable[hash % HASHTABLESIZE];
240	if (bucketp != NULL)
241		*bucketp = bucket;
242	for (hostent = *bucket; hostent != NULL; hostent = hostent->next) {
243		if (strcasecmp(hostent->name, host) == 0)
244			return (hostent);
245	}
246	return NULL;
247}
248
249static struct staticmap *
250find_staticmap_entry(const char *dir, struct staticmap ***bucketp)
251{
252	size_t hash;
253	const unsigned char *hashp;
254	unsigned char c;
255	struct staticmap **bucket;
256	struct staticmap *staticent;
257
258	/*
259	 * Cheesy hash function - just add all the characters in the
260	 * directory name together, and take it mod HASHTABLESIZE.
261	 */
262	hash = 0;
263	for (hashp = (const unsigned char *)dir; (c = *hashp) != '\0'; hashp++)
264		hash += c;
265	bucket = &static_hashtable[hash % HASHTABLESIZE];
266	if (bucketp != NULL)
267		*bucketp = bucket;
268	for (staticent = *bucket; staticent != NULL; staticent = staticent->next) {
269		if (strcmp(staticent->dir, dir) == 0)
270			return (staticent);
271	}
272	return NULL;
273}
274
275/*
276 * This assumes that a write lock on the fstab cache lock is held.
277 */
278static void
279clean_hashtables(void)
280{
281	int i;
282	struct fstabhost *host_ent, *next_host_ent;
283	struct staticmap *static_ent, *next_static_ent;
284
285	for (i = 0; i < HASHTABLESIZE; i++) {
286		for (host_ent = fstab_hashtable[i]; host_ent != NULL;
287		    host_ent = next_host_ent) {
288			next_host_ent = host_ent->next;
289			free(host_ent->name);
290			freefst_list(host_ent->fstab_ents);
291			free(host_ent);
292		}
293		fstab_hashtable[i] = NULL;
294	}
295
296	for (i = 0; i < HASHTABLESIZE; i++) {
297		for (static_ent = static_hashtable[i]; static_ent != NULL;
298		    static_ent = next_static_ent) {
299			next_static_ent = static_ent->next;
300			free(static_ent->dir);
301			free(static_ent->vfstype);
302			free(static_ent->mntops);
303			free(static_ent->host);
304			free(static_ent->localpath);
305			free(static_ent->spec);
306			free(static_ent);
307		}
308		static_hashtable[i] = NULL;
309	}
310}
311
312static void
313sort_fstab_entries(void)
314{
315	int i;
316	struct fstabhost *host_ent;
317	struct fstabnode *fst = NULL;
318	struct fstabnode *tfstlist, **tfstp, *fstnext;
319	size_t fstlen;
320	int duplicate;
321
322	for (i = 0; i < HASHTABLESIZE; i++) {
323		for (host_ent = fstab_hashtable[i]; host_ent != NULL;
324		    host_ent = host_ent->next) {
325			tfstlist = NULL;
326			for (fst = host_ent->fstab_ents; fst; fst = fstnext) {
327				fstnext = fst->fst_next;
328				fstlen = strlen(fst->fst_dir);
329				duplicate = 0;
330				for (tfstp = &tfstlist; *tfstp;
331				    tfstp = &((*tfstp)->fst_next)) {
332					if (fstlen < strlen((*tfstp)->fst_dir))
333						break;
334					duplicate = (strcmp(fst->fst_dir, (*tfstp)->fst_dir) == 0);
335					if (duplicate) {
336						/* disregard duplicate entry */
337						freefst_ent(fst);
338						break;
339					}
340				}
341				if (!duplicate) {
342					fst->fst_next = *tfstp;
343					*tfstp = fst;
344				}
345			}
346			host_ent->fstab_ents = tfstlist;
347		}
348	}
349}
350
351static const struct mntopt mopts_net[] = {
352	MOPT_NET,
353	{ NULL,		0, 0, 0 }
354};
355
356/*
357 * Flush out all information we got the last time we read all the
358 * fstab entries, and then read them and reconstruct that information.
359 *
360 * This assumes that a read lock is held on fstab_cache_lock.
361 * It will take a write lock on it; this means that all read
362 * locks will have been released before it gets the write lock.
363 * If it returns 0, the write lock is still held; if it returns an
364 * error, the write lock has been released.  (One reason it can
365 * return an error is that, for whatever reason, the attempt to
366 * get the write lock failed....)
367 */
368static int
369readfstab(void)
370{
371	int err;
372	struct fstab *fs;
373	char *p;
374	int is_local_entry;
375	mntoptparse_t mop;
376	int flags;
377	int altflags;
378	char *mntops, *url, *host, *localpath;
379
380	if (trace  > 1)
381		trace_prt(1, "readfstab called\n");
382
383	/*
384	 * Re-read fstab and rebuild the table.
385	 * We assume we were called with a reader lock; release
386	 * it and grab a writer lock, to ensure that nobody else
387	 * will be looking at it while we're modifying it.
388	 */
389	pthread_rwlock_unlock(&fstab_cache_lock);
390	err = pthread_rwlock_wrlock(&fstab_cache_lock);
391	if (err != 0) {
392		pr_msg("Error attempting to get write lock on fstab cache: %m");
393		return (err);	/* use the cached data */
394	}
395
396	/*
397	 * If the cache was populated recently, i.e. less than
398	 * MIN_CACHE_TIME seconds ago, then just ignore this
399	 * request to purge/repopulate the cache.  This avoids
400	 * spurious cache purging by because a process is
401	 * repeatedly looking up a name that's not cached.
402	 */
403	if (time(NULL) < min_cachetime)
404		return (0);
405
406	/*
407	 * Clean out the old entries, in case this is being called
408	 * because we failed to find an entry in a non-empty
409	 * cache.
410	 */
411	clean_hashtables();
412
413	/*
414	 * OK, scan the fstab and build our data structure.
415	 */
416	setfsent();
417
418	while ((fs = getfsent()) != NULL) {
419		char *vfstype;
420
421		/*
422		 * Is this an entry with an empty type, an "rw", a "ro"
423		 * entry, or none of those?
424		 */
425		if (fs->fs_type[0] != '\0' &&
426		    strcmp(fs->fs_type, FSTAB_RW) != 0 &&
427		    strcmp(fs->fs_type, FSTAB_RO) != 0) {
428			/* None of those - ignore it. */
429			continue;
430		}
431
432		/*
433		 * Does fs_spec begin with /?
434		 */
435		if (fs->fs_spec[0] == '/') {
436			/*
437			 * This is an entry for a local file system;
438			 * ignore it.
439			 */
440			continue;
441		}
442
443		/*
444		 * Does it begin with some form of XXX=, where XXX
445		 * is an identifier (letters, numbers, underscores,
446		 * and, just for fun, hyphens)?
447		 */
448		is_local_entry = 1;
449		for (p = fs->fs_spec; *p != '\0' && *p != '='; p++) {
450			if ((*p & 0x80) != 0) {
451				/*
452				 * Ow - non-ASCII.
453				 * Assume it's not a local entry.
454				 */
455				is_local_entry = 0;
456				break;
457			}
458			if (!isalnum(*p) && *p != '-' && *p != '_') {
459				/*
460				 * Something other than an identifier
461				 * character.  Not a local entry.
462				 */
463				is_local_entry = 0;
464				break;
465			}
466		}
467		if (is_local_entry) {
468			/*
469			 * We assume anything beginning with XXX= is
470			 * a local entry, along the lines of UUID=
471			 * or LABEL=.
472			 */
473			continue;
474		}
475
476		/*
477		 * Is "net" one of the mount options?
478		 */
479		flags = altflags = 0;
480		getmnt_silent = 1;
481		mop = getmntopts(fs->fs_mntops, mopts_net, &flags, &altflags);
482		if (mop == NULL) {
483			pr_msg("Couldn't parse mount options \"%s\" for %s: %m",
484			    fs->fs_mntops, fs->fs_spec);
485			continue;	/* give up on this */
486		}
487		freemntopts(mop);
488
489		/*
490		 * Extract the host name from fs_spec.
491		 */
492		p = strchr(fs->fs_spec, ':');
493		if (p == NULL) {
494			/*
495			 * No colon; one could consider that a path with
496			 * no host name, or a host name with no path;
497			 * in at least one case, the problem was that
498			 * the path was missing, so report it as that.
499			 */
500			pr_msg("Mount for %s has no path for the directory to mount", fs->fs_spec);
501			continue;	/* no path - ignore this */
502		}
503		if (p == fs->fs_spec) {
504			pr_msg("Mount for %s has an empty host name", fs->fs_spec);
505			continue;	/* empty host name - ignore this */
506		}
507		*p = '\0';		/* split into host name and the rest */
508		host = strdup(fs->fs_spec);
509		if (host == NULL)
510			goto outofmem;
511		localpath = strdup(p+1);
512		if (localpath == NULL) {
513			free(host);
514			goto outofmem;
515		}
516		/*
517		 * Put fs->fs_spec back the way it was, so we can use it
518		 * in error messages.
519		 */
520		*p = ':';
521
522		/*
523		 * Massage the mount options.
524		 */
525		err = process_fstab_mntopts(fs, &mntops, &url);
526		if (err == ENAMETOOLONG) {
527			pr_msg("Mount options for %s are too long",
528			    fs->fs_spec);
529			free(localpath);
530			free(host);
531			continue;	/* give up on this */
532		}
533		if (err == ENOMEM) {
534			free(localpath);
535			free(host);
536			goto outofmem;
537		}
538
539		/*
540		 * If the VFS type is empty, we treat it as "nfs", for
541		 * backwards compatibility with the old automounter.
542		 */
543		vfstype = fs->fs_vfstype;
544		if (vfstype[0] == '\0')
545			vfstype = "nfs";
546		if (strcmp(vfstype, "url") == 0) {
547			/* We must have a URL. */
548			if (url == NULL) {
549				pr_msg("Mount for %s has type url but no URL",
550				    fs->fs_spec);
551				free(mntops);
552				free(localpath);
553				free(host);
554				continue;
555			}
556		} else {
557			/* We must not have a URL. */
558			if (url != NULL) {
559				pr_msg("Mount for %s has type %s but has a URL",
560				    fs->fs_spec, vfstype);
561				free(mntops);
562				free(url);
563				free(localpath);
564				free(host);
565				continue;
566			}
567		}
568
569		if (altflags & FSTAB_MNT_NET) {
570			struct fstabnode *fst;
571			struct fstabhost *host_entry;
572			struct fstabhost **fstab_bucket;
573
574			/*
575			 * Entry has "net" - it's for -fstab.
576			 *
577			 * Allocate an entry for this fstab record.
578			 */
579			fst = calloc(1, sizeof (struct fstabnode));
580			if (fst == NULL) {
581				free(url);
582				free(mntops);
583				free(localpath);
584				free(host);
585				goto outofmem;
586			}
587
588			fst->fst_dir = localpath;
589			fst->fst_vfstype = strdup(vfstype);
590			if (fst->fst_vfstype == NULL) {
591				free(fst->fst_dir);
592				free(fst);
593				free(url);
594				free(mntops);
595				free(host);
596				goto outofmem;
597			}
598			fst->fst_mntops = mntops;	/* this is mallocated */
599			fst->fst_url = url;		/* as is this */
600
601			/*
602			 * Now add an entry for the host if we haven't already
603			 * done so.
604			 */
605			host_entry = find_host_entry(host, &fstab_bucket);
606			if (host_entry == NULL) {
607				/*
608				 * We found no entry for the host; allocate
609				 * one and add it to the hash table bucket.
610				 */
611				host_entry = malloc(sizeof (struct fstabhost));
612				if (host_entry == NULL) {
613					free(fst->fst_vfstype);
614					free(fst->fst_dir);
615					free(fst);
616					free(url);
617					free(mntops);
618					free(host);
619					goto outofmem;
620				}
621				host_entry->name = host;
622				host_entry->fstab_ents = fst;
623				host_entry->next = *fstab_bucket;
624				*fstab_bucket = host_entry;
625			} else {
626				/*
627				 * We found an entry; add the fstab
628				 * entry to its list of fstab entries.
629				 */
630				fst->fst_next = host_entry->fstab_ents;
631				host_entry->fstab_ents = fst;
632
633				/*
634				 * We don't need the host - we already
635				 * have it in the host entry.
636				 */
637				free(host);
638			}
639		} else {
640			/*
641			 * Entry doesn't have "net" - it's for -static.
642			 *
643			 * Do we already have an entry for this
644			 * directory?
645			 */
646			struct staticmap *static_ent;
647			struct staticmap **static_bucket;
648
649			if (strlen(fs->fs_file) == 0) {
650				pr_msg("Mount for %s has an empty mount point path",
651				    fs->fs_spec);
652				continue;	/* empty mount point path - ignore this */
653			}
654
655			static_ent = find_staticmap_entry(fs->fs_file,
656			    &static_bucket);
657			if (static_ent == NULL) {
658				/* No - make one. */
659				static_ent = malloc(sizeof (struct staticmap));
660				if (static_ent == NULL) {
661					free(url);
662					free(mntops);
663					free(localpath);
664					free(host);
665					goto outofmem;
666				}
667				static_ent->dir = strdup(fs->fs_file);
668				if (static_ent->dir == NULL) {
669					free(static_ent);
670					free(url);
671					free(mntops);
672					free(localpath);
673					free(host);
674					goto outofmem;
675				}
676				static_ent->vfstype = strdup(vfstype);
677				if (static_ent->vfstype == NULL) {
678					free(static_ent->dir);
679					free(static_ent);
680					free(url);
681					free(mntops);
682					free(localpath);
683					free(host);
684					goto outofmem;
685				}
686				static_ent->mntops = mntops;
687				static_ent->host = host;
688				if (url != NULL) {
689					static_ent->localpath = localpath;
690					static_ent->spec = url;
691				} else {
692					static_ent->localpath = localpath;
693					static_ent->spec = strdup(localpath);
694					if (static_ent->spec == NULL) {
695						free(static_ent->localpath);
696						free(static_ent->host);
697						free(static_ent->vfstype);
698						free(static_ent->dir);
699						free(static_ent);
700						free(url);
701						free(mntops);
702						goto outofmem;
703					}
704				}
705
706				/* Add it to the hash bucket. */
707				static_ent->next = *static_bucket;
708				*static_bucket = static_ent;
709			} else {
710				/* Yes - leave it. */
711				free(mntops);
712				free(url);
713				free(localpath);
714				free(host);
715			}
716		}
717	}
718	endfsent();
719
720	/*
721	 * Now, for each host entry, sort the list of fstab entries
722	 * by the length of the name; automountd expects that, so it
723	 * can get the mount order right.
724	 */
725	sort_fstab_entries();
726
727	/*
728	 * Update the min and max cache times
729	 */
730	min_cachetime = time(NULL) + MIN_CACHE_TIME;
731	max_cachetime = time(NULL) + RDDIR_CACHE_TIME * 2;
732
733	return (0);
734
735outofmem:
736	endfsent();
737	clean_hashtables();
738	pthread_rwlock_unlock(&fstab_cache_lock);
739	pr_msg("Memory allocation failed while reading fstab");
740	return (ENOMEM);
741}
742
743/*
744 * Look up a particular host in the fstab map hash table and, if we find it,
745 * run the callback routine on each entry in its fstab entry list.
746 */
747int
748fstab_process_host(const char *host, int (*callback)(struct fstabnode *, void *),
749    void *callback_arg)
750{
751	int err;
752	struct fstabhost *hostent;
753	struct fstabnode *fst;
754
755	/*
756	 * Get a read lock, so the cache doesn't get modified out
757	 * from under us.
758	 */
759	err = pthread_rwlock_rdlock(&fstab_cache_lock);
760	if (err != 0)
761		return (err);
762
763	hostent = find_host_entry(host, NULL);
764	if (hostent == NULL) {
765		/*
766		 * We've seen no entries for that host,
767		 * either because the cache has been purged
768		 * or we didn't find any the last time we
769		 * scanned the fstab entries.
770		 *
771		 * Try re-reading the fstab entries.
772		 */
773		err = readfstab();
774		if (err != 0) {
775			/*
776			 * That failed; give up.
777			 */
778			return (err);
779		}
780
781		/*
782		 * Now see if we can find the host.
783		 */
784		hostent = find_host_entry(host, NULL);
785		if (hostent == NULL) {
786			/*
787			 * No - give up.
788			 */
789			pthread_rwlock_unlock(&fstab_cache_lock);
790			return (-1);
791		}
792	}
793
794	/*
795	 * Run the callback on every entry in the fstab node list.
796	 * If the callback returns a non-zero value, stop and
797	 * return that value as an error.
798	 */
799	err = 0;
800	for (fst = hostent->fstab_ents; fst != NULL; fst = fst->fst_next) {
801		err = (*callback)(fst, callback_arg);
802		if (err != 0)
803			break;
804	}
805
806	/* We're done processing the list; release the lock. */
807	pthread_rwlock_unlock(&fstab_cache_lock);
808
809	return (err);
810}
811
812/*
813 * This assumes that a read or write lock on the fstab cache lock is held.
814 */
815static int
816scan_fstab(struct dir_entry **list, struct dir_entry **lastp)
817{
818	int i;
819	struct fstabhost *host_ent;
820	int err;
821
822	*lastp = NULL;
823	for (i = 0; i < HASHTABLESIZE; i++) {
824		for (host_ent = fstab_hashtable[i]; host_ent != NULL;
825		    host_ent = host_ent->next) {
826		    	/*
827			 * Add an entry for it if we haven't already
828			 * done so.
829			 *
830			 * A return of -1 means the name isn't valid.
831			 */
832			err = add_dir_entry(host_ent->name, NULL, NULL, list,
833			    lastp);
834			if (err != -1) {
835				if (err)
836					return (err);
837				assert(*lastp != NULL);
838			}
839		}
840	}
841	return (0);
842}
843
844/*
845 * Enumerate all the entries in the -fstab map.
846 * This is used by a readdir on the -fstab map; those are likely to
847 * be followed by stats on one or more of the entries in that map, so
848 * we populate the fstab map cache and return values from that.
849 */
850int
851getfstabkeys(struct dir_entry **list, int *error, int *cache_time)
852{
853	int err;
854	time_t timediff;
855	struct dir_entry *last;
856	char thishost[MAXHOSTNAMELEN];
857	char *p;
858
859	/*
860	 * Get a read lock, so the cache doesn't get modified out
861	 * from under us.
862	 */
863	err = pthread_rwlock_rdlock(&fstab_cache_lock);
864	if (err != 0) {
865		*error = err;
866		return (__NSW_UNAVAIL);
867	}
868
869	/*
870	 * Return the time until the current cache data times out.
871	 */
872	timediff = max_cachetime - time(NULL);
873	if (timediff < 0)
874		timediff = 0;
875	else if (timediff > INT_MAX)
876		timediff = INT_MAX;
877	*cache_time = (int)timediff;
878	*error = 0;
879	if (trace  > 1)
880		trace_prt(1, "getfstabkeys called\n");
881
882	/*
883	 * Get what we have cached.
884	 */
885	*error = scan_fstab(list, &last);
886	if (*error == 0) {
887		if (*list == NULL) {
888			/*
889			 * We've seen no fstab entries, either because
890			 * the cache has been purged or we didn't find
891			 * any the last time we scanned the fstab entries.
892			 *
893			 * Try re-reading the fstab entries.
894			 */
895			err = readfstab();
896			if (err != 0) {
897				/*
898				 * That failed; give up.
899				 */
900				*error = err;
901				return (__NSW_UNAVAIL);
902			}
903
904			/*
905			 * Get what we now have cached.
906			 */
907			*error = scan_fstab(list, &last);
908		}
909	}
910	if (*list != NULL) {
911		/*
912		 * list of entries found
913		 */
914		*error = 0;
915	}
916
917	if (*error == 0) {
918		/*
919		 * If we're a server, add an entry for this host's FQDN and
920		 * for the first component of its name; it will show up as
921		 * a symbolic link to "/".
922		 *
923		 * We do this, just as the old automounter did, so that, on
924		 * a server, you can refer to network home directories on the
925		 * machine with a /Network/Server/... path even if you haven't
926		 * yet made a mount record for the host, or if you're on an
927		 * Active Directory network and mount records are synthesized
928		 * when the user is looked up.  (See 5479706.)
929		 */
930		if (we_are_a_server()) {
931			/* (presumed) FQDN */
932			gethostname(thishost, MAXHOSTNAMELEN);
933			err = add_dir_entry(thishost, NULL, NULL, list, &last);
934			if (err != -1) {
935				if (err)
936					return (err);
937				assert(last != NULL);
938			}
939
940			/* First component. */
941			p = strchr(thishost, '.');
942			if (p != NULL) {
943				*p = '\0';
944				err = add_dir_entry(thishost, NULL, NULL, list,
945				    &last);
946				if (err != -1) {
947					if (err)
948						return (err);
949					assert(last != NULL);
950				}
951			}
952		}
953	}
954
955	/* We're done processing the list; release the lock. */
956	pthread_rwlock_unlock(&fstab_cache_lock);
957
958	return (__NSW_SUCCESS);
959}
960
961/*
962 * Check whether we have any entries in the -fstab map.
963 * This is used by automount to decide whether to mount that map
964 * or not.
965 */
966int
967havefstabkeys(void)
968{
969	int err;
970	int ret;
971	int i;
972
973	/*
974	 * Are we a server?  If so, we always have -fstab entries,
975	 * as there's always the selflink.
976	 */
977	if (we_are_a_server())
978		return (1);
979
980	/*
981	 * Get a read lock, so the cache doesn't get modified out
982	 * from under us.
983	 */
984	err = pthread_rwlock_rdlock(&fstab_cache_lock);
985	if (err != 0)
986		return (0);
987
988	if (trace  > 1)
989		trace_prt(1, "havefstabkeys called\n");
990
991	/*
992	 * Check what we have cached.
993	 */
994	for (i = 0; i < HASHTABLESIZE; i++) {
995		if (fstab_hashtable[i] != NULL) {
996			/*
997			 * We have at least one entry.
998			 */
999			ret = 1;
1000			goto done;
1001		}
1002	}
1003
1004	/*
1005	 * We've seen no entries, either because the cache has
1006	 * been purged or we didn't find any the last time we
1007	 * scanned the fstab entries.
1008	 *
1009	 * Try re-reading the fstab entries.
1010	 */
1011	err = readfstab();
1012	if (err != 0) {
1013		/*
1014		 * That failed; give up.
1015		 */
1016		ret = 0;
1017		goto done;
1018	}
1019
1020	/*
1021	 * Check what we now have cached.
1022	 */
1023	for (i = 0; i < HASHTABLESIZE; i++) {
1024		if (fstab_hashtable[i] != NULL) {
1025			/*
1026			 * We have at least one entry.
1027			 */
1028			ret = 1;
1029			goto done;
1030		}
1031	}
1032
1033	/*
1034	 * Nothing found.
1035	 */
1036	ret = 0;
1037
1038done:
1039
1040	/* We're done processing the list; release the lock. */
1041	pthread_rwlock_unlock(&fstab_cache_lock);
1042
1043	return (ret);
1044}
1045
1046/*
1047 * Load the -static direct map.
1048 */
1049int
1050loaddirect_static(local_map, opts, stack, stkptr)
1051	char *local_map, *opts;
1052	char **stack, ***stkptr;
1053{
1054	int done = 0;
1055	int i;
1056	struct staticmap *static_ent;
1057
1058	/*
1059	 * Get a read lock, so the cache doesn't get modified out
1060	 * from under us.
1061	 */
1062	if (pthread_rwlock_rdlock(&fstab_cache_lock) != 0)
1063		return (__NSW_UNAVAIL);
1064
1065	/*
1066	 * Get what we have cached.
1067	 */
1068	for (i = 0; i < HASHTABLESIZE; i++) {
1069		for (static_ent = static_hashtable[i]; static_ent != NULL;
1070		    static_ent = static_ent->next) {
1071			dirinit(static_ent->dir, local_map, opts, 1, stack, stkptr);
1072			done++;
1073		}
1074	}
1075
1076	if (!done) {
1077		/*
1078		 * We've seen no entries, either because the cache has
1079		 * been purged or we didn't find any the last time we
1080		 * scanned the fstab entries.
1081		 *
1082		 * Try re-reading the fstab entries.
1083		 */
1084		if (readfstab() != 0) {
1085			/*
1086			 * That failed; give up.
1087			 */
1088			return (__NSW_UNAVAIL);
1089		}
1090
1091		/*
1092		 * Get what we now have cached.
1093		 */
1094		for (i = 0; i < HASHTABLESIZE; i++) {
1095			for (static_ent = static_hashtable[i];
1096			    static_ent != NULL;
1097			    static_ent = static_ent->next) {
1098				dirinit(static_ent->dir, local_map, opts, 1, stack, stkptr);
1099				done++;
1100			}
1101		}
1102	}
1103
1104	pthread_rwlock_unlock(&fstab_cache_lock);
1105	return (done ? __NSW_SUCCESS : __NSW_NOTFOUND);
1106}
1107
1108/*
1109 * Find the -static map entry corresponding to a given mount point.
1110 *
1111 * We return with the read lock held, so that the cache doesn't
1112 * get cleared, and all the entries freed, while somebody's holding
1113 * onto an entry.  The holder must call release_staticmap_entry()
1114 * with the entry; for now, all that will do is release the rwlock.
1115 */
1116struct staticmap *
1117get_staticmap_entry(const char *dir)
1118{
1119	struct staticmap *static_ent;
1120
1121	/*
1122	 * Get a read lock, so the cache doesn't get modified out
1123	 * from under us.
1124	 */
1125	if (pthread_rwlock_rdlock(&fstab_cache_lock) != 0)
1126		return (NULL);
1127
1128	/*
1129	 * Get what we have cached.
1130	 */
1131	static_ent = find_staticmap_entry(dir, NULL);
1132
1133	if (static_ent == NULL) {
1134		/*
1135		 * We've found no entry, either because the cache has
1136		 * been purged or we didn't find any the last time we
1137		 * scanned the fstab entries.
1138		 *
1139		 * Try re-reading the fstab entries.
1140		 */
1141		if (readfstab() != 0) {
1142			/*
1143			 * That failed; give up.
1144			 */
1145			pthread_rwlock_unlock(&fstab_cache_lock);
1146			return (NULL);
1147		}
1148
1149		/*
1150		 * Check what we now have cached.
1151		 */
1152		static_ent = find_staticmap_entry(dir, NULL);
1153
1154		/*
1155		 * If we still have nothing, release the read lock,
1156		 * as we're not returning a pointer to something
1157		 * in the cache.
1158		 */
1159		if (static_ent == NULL)
1160			pthread_rwlock_unlock(&fstab_cache_lock);
1161	}
1162
1163	return (static_ent);
1164}
1165
1166/*
1167 * Indicate that we're done with a -static map entry returned by
1168 * get_staticmap_entry().
1169 */
1170void
1171release_staticmap_entry(__unused struct staticmap *static_ent)
1172{
1173	pthread_rwlock_unlock(&fstab_cache_lock);
1174}
1175
1176/*
1177 * Purge the fstab cache; if scheduled is true, do so only if it's
1178 * stale, otherwise do it unconditionally.
1179 */
1180void
1181clean_fstab_cache(int scheduled)
1182{
1183	/*
1184	 * If this is a scheduled cache cleanup, and the cache is still
1185	 * valid, don't purge it.
1186	 */
1187	if (scheduled && max_cachetime > time(NULL))
1188		return;
1189
1190	/*
1191	 * Lock the cache against all operations.
1192	 */
1193	if (pthread_rwlock_wrlock(&fstab_cache_lock) != 0)
1194		return;
1195
1196	/*
1197	 * Clean out the old entries.
1198	 */
1199	clean_hashtables();
1200
1201	/*
1202	 * Reset the minimum cache time, so that we'll reread the fstab
1203	 * entries; we have to do so, as we discarded the results of
1204	 * the last read.
1205	 */
1206	min_cachetime = 0;
1207
1208	pthread_rwlock_unlock(&fstab_cache_lock);
1209}
1210