/* * 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); }
/* * 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); }