#include <rpc/rpc.h>
#include "brpc.h"
#include <rpc/types.h>
#include <rpc/auth.h>
#include <rpc/xdr.h>
#include <rpc/rpc_msg.h>
#include <sys/t_lock.h>
#include "clnt.h"
#include <rpcsvc/mount.h>
#include <st_pathname.h>
#include <sys/errno.h>
#include <sys/promif.h>
#include "nfs_inet.h"
#include "socket_inet.h"
#include <rpcsvc/nfs_prot.h>
#include <rpcsvc/nfs4_prot.h>
#include <sys/types.h>
#include <sys/salib.h>
#include <sys/sacache.h>
#include <sys/stat.h>
#include <sys/bootvfs.h>
#include <sys/bootdebug.h>
#include "mac.h"
static int root_inum = 1;
static int next_inum = 1;
#define dprintf if (boothowto & RB_DEBUG) printf
static int stlookuppn(struct st_pathname *pnp, struct nfs_file *cfile,
bool_t needroothandle);
int
lookup(char *pathname, struct nfs_file *cur_file, bool_t needroothandle)
{
struct st_pathname pnp;
int error;
static char lkup_path[NFS_MAXPATHLEN];
pnp.pn_buf = &lkup_path[0];
bzero(pnp.pn_buf, NFS_MAXPATHLEN);
error = stpn_get(pathname, &pnp);
if (error)
return (error);
error = stlookuppn(&pnp, cur_file, needroothandle);
return (error);
}
static int
stlookuppn(struct st_pathname *pnp, struct nfs_file *cfile,
bool_t needroothandle)
{
char component[NFS_MAXNAMLEN+1];
int nlink = 0;
int error = 0;
int dino, cino;
struct nfs_file *cdp = NULL;
*cfile = roothandle;
dino = root_inum;
begin:
component[0] = '\0';
if (stpn_peekchar(pnp) == '/') {
if (!needroothandle)
*cfile = roothandle;
dino = root_inum;
stpn_skipslash(pnp);
}
next:
if (!cfile_is_dir(cfile)) {
error = ENOTDIR;
goto bad;
}
error = stpn_stripcomponent(pnp, component);
if (error)
goto bad;
if (component[0] == '\0')
return (0);
if (strcmp(component, "..") == 0) {
if (cfile == &roothandle)
goto skip;
}
cino = get_dcache(mac_get_dev(), component, dino);
if (cino == -1)
return (ENOENT);
#ifdef DEBUG
dprintf("lookup: component %s pathleft %s\n", component, pnp->pn_path);
#endif
if ((cino == 0) ||
((cdp = (struct nfs_file *)get_icache(mac_get_dev(), cino)) == 0)) {
struct nfs_file *lkp;
error = -1;
switch (cfile->version) {
case NFS_VERSION:
lkp = nfslookup(cfile, component, &error);
break;
case NFS_V3:
lkp = nfs3lookup(cfile, component, &error);
break;
case NFS_V4:
lkp = nfs4lookup(cfile, component, &error);
break;
default:
printf("lookup: NFS Version %d not supported\n",
cfile->version);
lkp = NULL;
break;
}
if (error == -1) {
printf("lookup: lookup RPC error\n");
return (error);
}
if (lkp == NULL) {
if ((error != NFSERR_NOENT) &&
(error != NFS3ERR_NOENT) &&
(error != NFS4ERR_NOENT)) {
#ifdef DEBUG
dprintf("lookup: lkp is NULL with error %d\n", error);
#endif
return (error);
}
#ifdef DEBUG
dprintf("lookup: lkp is NULL with error %d\n", error);
#endif
set_dcache(mac_get_dev(), component, dino, -1);
return (error);
}
if (cdp = (struct nfs_file *)
bkmem_alloc(sizeof (struct nfs_file))) {
if (!cino)
cino = ++next_inum;
*cdp = *lkp;
set_dcache(mac_get_dev(), component, dino, cino);
set_icache(mac_get_dev(), cino, cdp,
sizeof (struct nfs_file));
} else {
cino = 0;
cdp = lkp;
}
}
dino = cino;
if (cfile_is_lnk(cdp)) {
struct st_pathname linkpath;
static char path_tmp[NFS_MAXPATHLEN];
char *pathp;
linkpath.pn_buf = &path_tmp[0];
nlink++;
if (nlink > MAXSYMLINKS) {
error = ELOOP;
goto bad;
}
switch (cdp->version) {
case NFS_VERSION:
error = nfsgetsymlink(cdp, &pathp);
break;
case NFS_V3:
error = nfs3getsymlink(cdp, &pathp);
break;
case NFS_V4:
error = nfs4getsymlink(cdp, &pathp);
break;
default:
printf("getsymlink: NFS Version %d not supported\n",
cdp->version);
error = ENOTSUP;
break;
}
if (error)
goto bad;
(void) stpn_get(pathp, &linkpath);
if (stpn_pathleft(&linkpath) == 0)
(void) stpn_set(&linkpath, ".");
error = stpn_combine(pnp, &linkpath);
if (error)
goto bad;
goto begin;
}
if (needroothandle) {
roothandle = *cdp;
needroothandle = FALSE;
}
*cfile = *cdp;
skip:
if (stpn_pathleft(pnp) == 0) {
(void) stpn_set(pnp, component);
return (0);
}
stpn_skipslash(pnp);
goto next;
bad:
return (error);
}