Example #1
0
/*
 * XXX - Serialize calls to fsgetmntlist, so that threads can get consistent
 * snapshots of the in-kernel mnttab.  This function should be removed
 * once getextmntent is made MT-safe and callers can invoke fsgetmntlist
 * directly.
 */
struct mntlist *
getmntlist()
{
	struct mntlist *mntl;

	(void) mutex_lock(&mnttab_lock);
	mntl = fsgetmntlist();
	(void) mutex_unlock(&mnttab_lock);
	return (mntl);
}
Example #2
0
/*
 * find_lofsentry() searches for the real path which this requested LOFS path
 * (rpath) shadows. If found, it will return the sharetab entry of
 * the real path that corresponds to the LOFS path.
 * We first search mnttab to see if the requested path is an automounted
 * path. If it is an automounted path, it will trigger the mount by stat()ing
 * the requested path. Note that it is important to check that this path is
 * actually an automounted path, otherwise we would stat() a path which may
 * turn out to be NFS and block indefinitely on a dead server. The automounter
 * times-out if the server is dead, so there's no risk of hanging this
 * thread waiting for stat().
 * After the mount has been triggered (if necessary), we look for a
 * mountpoint of type LOFS (by searching /etc/mnttab again) which
 * is a substring of the rpath. If found, we construct a new path by
 * concatenating the mnt_special and the remaining of rpath, call findentry()
 * to make sure the 'real path' is shared.
 */
static struct share *
find_lofsentry(char *rpath, int *done_flag)
{
	struct stat r_stbuf;
	mntlist_t *ml, *mntl, *mntpnt = NULL;
	struct share *retcode = NULL;
	char tmp_path[MAXPATHLEN];
	int mntpnt_len = 0, tmp;
	char *p1, *p2;

	if ((*done_flag)++)
		return (retcode);

	/*
	 * While fsgetmntlist() uses lockf() to
	 * lock the mnttab before reading it in,
	 * the lock ignores threads in the same process.
	 * Read in the mnttab with the protection of a mutex.
	 */
	(void) mutex_lock(&mnttab_lock);
	mntl = fsgetmntlist();
	(void) mutex_unlock(&mnttab_lock);

	/*
	 * Obtain the mountpoint for the requested path.
	 */
	for (ml = mntl; ml; ml = ml->mntl_next) {
		for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
			*p1 == *p2 && *p1; p1++, p2++);
		if (is_substring(&p1, &p2) &&
		    (tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len) {
			mntpnt = ml;
			mntpnt_len = tmp;
		}
	}

	/*
	 * If the path needs to be autoFS mounted, trigger the mount by
	 * stat()ing it. This is determined by checking whether the
	 * mountpoint we just found is of type autofs.
	 */
	if (mntpnt != NULL &&
	    strcmp(mntpnt->mntl_mnt->mnt_fstype, "autofs") == 0) {
		/*
		 * The requested path is a substring of an autoFS filesystem.
		 * Trigger the mount.
		 */
		if (stat(rpath, &r_stbuf) < 0) {
			if (verbose)
				syslog(LOG_NOTICE, "%s: %m", rpath);
			goto done;
		}
		if ((r_stbuf.st_mode & S_IFMT) == S_IFDIR) {
			/*
			 * The requested path is a directory, stat(2) it
			 * again with a trailing '.' to force the autoFS
			 * module to trigger the mount of indirect
			 * automount entries, such as /net/jurassic/.
			 */
			if (strlen(rpath) + 2 > MAXPATHLEN) {
				if (verbose) {
					syslog(LOG_NOTICE,
						"%s/.: exceeds MAXPATHLEN %d",
						rpath, MAXPATHLEN);
				}
				goto done;
			}
			(void) strcpy(tmp_path, rpath);
			(void) strcat(tmp_path, "/.");

			if (stat(tmp_path, &r_stbuf) < 0) {
				if (verbose)
					syslog(LOG_NOTICE, "%s: %m", tmp_path);
				goto done;
			}
		}
		/*
		 * The mount has been triggered, re-read mnttab to pick up
		 * the changes made by autoFS.
		 */
		fsfreemntlist(mntl);
		(void) mutex_lock(&mnttab_lock);
		mntl = fsgetmntlist();
		(void) mutex_unlock(&mnttab_lock);
	}

	/*
	 * The autoFS mountpoint has been triggered if necessary,
	 * now search mnttab again to determine if the requested path
	 * is an LOFS mount of a shared path.
	 */
	mntpnt_len = 0;
	for (ml = mntl; ml; ml = ml->mntl_next) {
		if (strcmp(ml->mntl_mnt->mnt_fstype, "lofs"))
			continue;

		for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
				*p1 == *p2 && *p1; p1++, p2++);

		if (is_substring(&p1, &p2) &&
		    ((tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len)) {
			mntpnt_len = tmp;

			if ((strlen(ml->mntl_mnt->mnt_special) + strlen(p2)) >
			    MAXPATHLEN) {
				if (verbose) {
					syslog(LOG_NOTICE, "%s%s: exceeds %d",
						ml->mntl_mnt->mnt_special, p2,
						MAXPATHLEN);
				}
				if (retcode)
					sharefree(retcode);
				retcode = NULL;
				goto done;
			}

			(void) strcpy(tmp_path, ml->mntl_mnt->mnt_special);
			(void) strcat(tmp_path, p2);
			if (retcode)
				sharefree(retcode);
			retcode = findentry(tmp_path);
		}
	}

	if (retcode) {
		assert(strlen(tmp_path) > 0);
		(void) strcpy(rpath, tmp_path);
	}

done:
	fsfreemntlist(mntl);
	return (retcode);
}