Print this page




   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.
   7  *
   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.
  12  *
  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]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright 2016 Joyent, Inc.
  25  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  26  */
  27 
  28 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  29 /*        All Rights Reserved   */
  30 
  31 /*
  32  * University Copyright- Copyright (c) 1982, 1986, 1988
  33  * The Regents of the University of California
  34  * All Rights Reserved
  35  *
  36  * University Acknowledgment- Portions of this document are derived from
  37  * software developed by the University of California, Berkeley, and its
  38  * contributors.
  39  */
  40 
  41 #include <sys/types.h>
  42 #include <sys/param.h>
  43 #include <sys/systm.h>
  44 #include <sys/cpuvar.h>


 962                         break;
 963                 VN_RELE(vp);
 964                 vp = cvp;
 965 
 966                 if (vn_ismntpt(vp) && traverse(&vp) != 0)
 967                         break;
 968 
 969                 if (vn_compare(vp, vrootp)) {
 970                         ret = path + (pn.pn_path - pn.pn_buf);
 971                         break;
 972                 }
 973         }
 974 
 975         VN_RELE(vp);
 976         pn_free(&pn);
 977 
 978         return (ret);
 979 }
 980 
 981 /*
 982  * Clean a stale v_path from a vnode.  This is only performed if the v_path has
 983  * not been altered since it was found to be stale
 984  */
 985 static void
 986 vnode_clear_vpath(vnode_t *vp, char *vpath_old)
 987 {
 988         mutex_enter(&vp->v_lock);
 989         if (vp->v_path != vn_vpath_empty && vp->v_path == vpath_old) {
 990                 vp->v_path = vn_vpath_empty;
 991                 mutex_exit(&vp->v_lock);
 992                 kmem_free(vpath_old, strlen(vpath_old) + 1);
 993         } else {
 994                 mutex_exit(&vp->v_lock);
 995         }
 996 }
 997 
 998 /*
 999  * Validate that a pathname refers to a given vnode.
1000  */
1001 static int
1002 vnode_valid_pn(vnode_t *vp, vnode_t *vrootp, pathname_t *pn, pathname_t *rpn,
1003     int flags, cred_t *cr)
1004 {
1005         vnode_t *compvp;
1006         /*
1007          * If we are in a zone or a chroot environment, then we have to
1008          * take additional steps, since the path to the root might not
1009          * be readable with the current credentials, even though the
1010          * process can legitmately access the file.  In this case, we
1011          * do the following:
1012          *
1013          * lookuppnvp() with all privileges to get the resolved path.
1014          * call localpath() to get the local portion of the path, and
1015          * continue as normal.
1016          *
1017          * If the the conversion to a local path fails, then we continue
1018          * as normal.  This is a heuristic to make process object file
1019          * paths available from within a zone.  Because lofs doesn't
1020          * support page operations, the vnode stored in the seg_t is
1021          * actually the underlying real vnode, not the lofs node itself.
1022          * Most of the time, the lofs path is the same as the underlying
1023          * vnode (for example, /usr/lib/libc.so.1).
1024          */
1025         if (vrootp != rootdir) {
1026                 char *local = NULL;
1027 
1028                 VN_HOLD(rootdir);
1029                 if (lookuppnvp(pn, rpn, FOLLOW, NULL, &compvp, rootdir,
1030                     rootdir, kcred) == 0) {
1031                         local = localpath(rpn->pn_path, vrootp, kcred);
1032                         VN_RELE(compvp);
1033                 }
1034 
1035                 /*
1036                  * The original pn was changed through lookuppnvp().
1037                  * Set it to local for next validation attempt.
1038                  */
1039                 if (local) {
1040                         (void) pn_set(pn, local);
1041                 } else {
1042                         return (1);
1043                 }
1044         }
1045 
1046         /*
1047          * We should have a local path at this point, so start the search from
1048          * the root of the current process.
1049          */
1050         VN_HOLD(vrootp);
1051         if (vrootp != rootdir)
1052                 VN_HOLD(vrootp);
1053         if (lookuppnvp(pn, rpn, FOLLOW | flags, NULL, &compvp, vrootp, vrootp,
1054             cr) == 0) {
1055                 /*
1056                  * Check to see if the returned vnode is the same as the one we
1057                  * expect.
1058                  */
1059                 if (vn_compare(vp, compvp) ||
1060                     vnode_match(vp, compvp, cr)) {
1061                         VN_RELE(compvp);
1062                         return (0);
1063                 } else {
1064                         VN_RELE(compvp);
1065                 }
1066         }
1067 
1068         return (1);
1069 }
1070 
1071 /*
1072  * Struct for tracking vnodes with invalidated v_path entries during a
1073  * dirtopath reverse lookup.  By keepeing adequate state, those vnode can be
1074  * revisted to populate v_path.
1075  */
1076 struct dirpath_walk {
1077         struct dirpath_walk     *dw_next;
1078         vnode_t                 *dw_vnode;
1079         vnode_t                 *dw_pvnode;
1080         size_t                  dw_len;
1081         char                    *dw_name;
1082 };
1083 
1084 /*
1085  * Given a directory, return the full, resolved path.  This looks up "..",
1086  * searches for the given vnode in the parent, appends the component, etc.  It
1087  * is used to implement vnodetopath() and getcwd() when the cached path fails.
1088  */
1089 static int
1090 dirtopath(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, int flags,
1091     cred_t *cr)
1092 {
1093         pathname_t      pn, rpn, emptypn;
1094         vnode_t         *pvp = NULL, *startvp = vp;
1095         int             err = 0;

1096         size_t          complen;

1097         dirent64_t      *dp;
1098         char            *bufloc, *dbuf;
1099         const size_t    dlen = DIRENT64_RECLEN(MAXPATHLEN);
1100         struct dirpath_walk *dw_chain = NULL, *dw_entry;
1101 
1102         /* Operation only allowed on directories */
1103         ASSERT(vp->v_type == VDIR);
1104 
1105         /* We must have at least enough space for "/" */
1106         if (buflen < 2)
1107                 return (ENAMETOOLONG);
1108 
1109         /* Start at end of string with terminating null */
1110         bufloc = &buf[buflen - 1];
1111         *bufloc = '\0';
1112 
1113         pn_alloc(&pn);
1114         pn_alloc(&rpn);
1115         dbuf = kmem_alloc(dlen, KM_SLEEP);
1116         bzero(&emptypn, sizeof (emptypn));
1117 
1118         /*
1119          * Begin with an additional reference on vp.  This will be decremented
1120          * during the loop.
1121          */
1122         VN_HOLD(vp);
1123 
1124         for (;;) {
1125                 int vprivs;
1126                 hrtime_t cached_stamp;
1127 
1128                 /*
1129                  * Return if we've reached the root.  If the buffer is empty,
1130                  * return '/'.  We explicitly don't use vn_compare(), since it
1131                  * compares the real vnodes.  A lofs mount of '/' would produce
1132                  * incorrect results otherwise.
1133                  */
1134                 if (VN_CMP(vrootp, vp)) {
1135                         if (*bufloc == '\0')
1136                                 *--bufloc = '/';
1137                         break;
1138                 }
1139 
1140                 /*
1141                  * If we've reached the VFS root, something has gone wrong.  We
1142                  * should have reached the root in the above check.  The only
1143                  * explantation is that 'vp' is not contained withing the given
1144                  * root, in which case we return EPERM.
1145                  */
1146                 if (VN_CMP(rootdir, vp)) {
1147                         err = EPERM;
1148                         goto out;
1149                 }
1150 
1151                 /*










































1152                  * Shortcut: see if this vnode has correct v_path. If so,
1153                  * we have the work done.
1154                  */
1155                 mutex_enter(&vp->v_lock);
1156                 if (vp->v_path != vn_vpath_empty &&
1157                     pn_set(&pn, vp->v_path) == 0) {
1158                         cached_stamp = vp->v_path_stamp;
1159                         mutex_exit(&vp->v_lock);
1160                         rpn.pn_path = rpn.pn_buf;
1161 
1162                         /* Ensure the v_path pointing to correct vnode */
1163                         if (vnode_valid_pn(vp, vrootp, &pn, &rpn, flags,
1164                             cr) == 0) {









1165                                 complen = strlen(rpn.pn_path);
1166                                 bufloc -= complen;
1167                                 if (bufloc < buf) {
1168                                         err = ERANGE;
1169                                         goto out;
1170                                 }
1171                                 bcopy(rpn.pn_path, bufloc, complen);

1172                                 break;
1173                         } else {
1174                                 /*
1175                                  * Immediately nuke cached v_path entries known
1176                                  * to be invalid.
1177                                  */
1178                                 vn_clearpath(vp, cached_stamp);
1179                         }

1180                 } else {
1181                         mutex_exit(&vp->v_lock);
1182                 }



1183 
1184                 /*
1185                  * Shortcuts failed, search for this vnode in its parent.  If
1186                  * this is a mountpoint, then get the vnode underneath.
1187                  */
1188                 if (vp->v_flag & VROOT)
1189                         vp = vn_under(vp);
1190                 if ((err = VOP_LOOKUP(vp, "..", &pvp, &emptypn, 0, vrootp, cr,
1191                     NULL, NULL, NULL)) != 0)
1192                         goto out;
1193 
1194                 /*
1195                  * With extended attributes, it's possible for a directory to
1196                  * have a parent that is a regular file.  Check for that here.
1197                  */
1198                 if (pvp->v_type != VDIR) {
1199                         err = ENOTDIR;
1200                         goto out;
1201                 }
1202 
1203                 /*
1204                  * If this is true, something strange has happened.  This is
1205                  * only true if we are the root of a filesystem, which should
1206                  * have been caught by the check above.
1207                  */
1208                 if (VN_CMP(pvp, vp)) {
1209                         err = ENOENT;
1210                         goto out;
1211                 }
1212 
1213                 /*
1214                  * Check if we have read and search privilege so, that
1215                  * we can lookup the path in the directory
1216                  */
1217                 vprivs = (flags & LOOKUP_CHECKREAD) ? VREAD | VEXEC : VEXEC;
1218                 if ((err = VOP_ACCESS(pvp, vprivs, 0, cr, NULL)) != 0) {
1219                         goto out;
1220                 }
1221 
1222                 /*
































1223                  * Search the parent directory for the entry corresponding to
1224                  * this vnode.
1225                  */
1226                 if ((err = dirfindvp(vrootp, pvp, vp, cr, dbuf, dlen, &dp))
1227                     != 0)
1228                         goto out;
1229                 complen = strlen(dp->d_name);
1230                 bufloc -= complen;
1231                 if (bufloc <= buf) {
1232                         err = ENAMETOOLONG;
1233                         goto out;
1234                 }
1235                 bcopy(dp->d_name, bufloc, complen);
1236 
1237                 /* Prepend a slash to the current path.  */
1238                 *--bufloc = '/';
1239 
1240                 /*
1241                  * Record the name and directory for later reconstruction and
1242                  * link it up with the others.
1243                  */
1244                 dw_entry = kmem_alloc(sizeof (*dw_entry), KM_SLEEP);
1245                 dw_entry->dw_name = kmem_alloc(complen + 1, KM_SLEEP);
1246                 VN_HOLD(dw_entry->dw_vnode = vp);
1247                 VN_HOLD(dw_entry->dw_pvnode = pvp);
1248                 bcopy(dp->d_name, dw_entry->dw_name, complen + 1);
1249                 dw_entry->dw_len = complen;
1250                 dw_entry->dw_next = dw_chain;
1251                 dw_chain = dw_entry;
1252 
1253                 /* And continue with the next component */
1254                 VN_RELE(vp);
1255                 vp = pvp;
1256                 pvp = NULL;
1257         }
1258 
1259         /*
1260          * Place the path at the beginning of the buffer.
1261          */
1262         if (bufloc != buf)
1263                 ovbcopy(bufloc, buf, buflen - (bufloc - buf));
1264 
1265 out:
1266         /*
1267          * Walk over encountered directory entries which were afflicted with a
1268          * stale or absent v_path.  If the dirtopath was successful, we should
1269          * possess the necessary information to populate all of them with a
1270          * valid v_path.
1271          *
1272          * While processing this list, it is safe to call vn_setpath despite
1273          * the fact that racing vnode actions may have altered v_path entries
1274          * while the above loopwas still executing.  Any updated entries will
1275          * have a newer v_path_stamp value which prevents an invalid overwrite.
1276          *
1277          * If an error was encountered during the search, freeing the chain is
1278          * still required.
1279          */
1280         dw_entry = dw_chain;
1281         while (dw_entry != NULL) {
1282                 struct dirpath_walk *next = dw_entry->dw_next;
1283 
1284                 if (err == 0) {
1285                         vn_setpath(NULL, dw_entry->dw_pvnode,
1286                             dw_entry->dw_vnode, dw_entry->dw_name,
1287                             dw_entry->dw_len);
1288                 }
1289 
1290                 VN_RELE(dw_entry->dw_vnode);
1291                 VN_RELE(dw_entry->dw_pvnode);
1292                 kmem_free(dw_entry->dw_name, dw_entry->dw_len + 1);
1293                 kmem_free(dw_entry, sizeof (*dw_entry));
1294                 dw_entry = next;
1295         }
1296 
1297         /*
1298          * If the error was ESTALE and the current directory to look in
1299          * was the root for this lookup, the root for a mounted file
1300          * system, or the starting directory for lookups, then
1301          * return ENOENT instead of ESTALE.  In this case, no recovery
1302          * is possible by the higher level.  If ESTALE was returned for
1303          * some intermediate directory along the path, then recovery
1304          * is potentially possible and retrying from the higher level
1305          * will either correct the situation by purging stale cache
1306          * entries or eventually get back to the point where no recovery
1307          * is possible.
1308          */
1309         if (err == ESTALE &&
1310             (VN_CMP(vp, vrootp) || (vp->v_flag & VROOT) || vp == startvp))
1311                 err = ENOENT;
1312 
1313         kmem_free(dbuf, dlen);
1314         VN_RELE(vp);
1315         if (pvp)
1316                 VN_RELE(pvp);
1317         pn_free(&pn);
1318         pn_free(&rpn);
1319 
1320         return (err);
1321 }
1322 
1323 /*
1324  * The additional flag, LOOKUP_CHECKREAD, is used to enforce artificial
1325  * constraints in order to be standards compliant.  For example, if we have
1326  * the cached path of '/foo/bar', and '/foo' has permissions 100 (execute
1327  * only), then we can legitimately look up the path to the current working
1328  * directory without needing read permission.  Existing standards tests,
1329  * however, assume that we are determining the path by repeatedly looking up
1330  * "..".  We need to keep this behavior in order to maintain backwards
1331  * compatibility.
1332  */
1333 static int
1334 vnodetopath_common(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen,
1335     cred_t *cr, int flags)
1336 {
1337         pathname_t pn;
1338         int ret = 0;
1339         vnode_t *realvp;
1340         boolean_t doclose = B_FALSE;


1341 
1342         /*
1343          * If vrootp is NULL, get the root for curproc.  Callers with any other
1344          * requirements should pass in a different vrootp.
1345          */
1346         if (vrootp == NULL) {
1347                 proc_t *p = curproc;
1348 
1349                 mutex_enter(&p->p_lock);
1350                 if ((vrootp = PTOU(p)->u_rdir) == NULL)
1351                         vrootp = rootdir;
1352                 VN_HOLD(vrootp);
1353                 mutex_exit(&p->p_lock);
1354         } else {
1355                 VN_HOLD(vrootp);
1356         }
1357 
1358         /*
1359          * This is to get around an annoying artifact of the /proc filesystem,
1360          * which is the behavior of {cwd/root}.  Trying to resolve this path
1361          * will result in /proc/pid/cwd instead of whatever the real working
1362          * directory is.  We can't rely on VOP_REALVP(), since that will break
1363          * lofs.  The only difference between procfs and lofs is that opening
1364          * the file will return the underling vnode in the case of procfs.
1365          */
1366         if (vp->v_type == VDIR && VOP_REALVP(vp, &realvp, NULL) == 0 &&
1367             realvp != vp) {
1368                 VN_HOLD(vp);
1369                 if (VOP_OPEN(&vp, FREAD, cr, NULL) == 0)
1370                         doclose = B_TRUE;
1371                 else
1372                         VN_RELE(vp);
1373         }
1374 


1375         /*
1376          * Check to see if we have a valid cached path in the vnode.
1377          */
1378         pn_alloc(&pn);
1379         mutex_enter(&vp->v_lock);
1380         if (vp->v_path != vn_vpath_empty) {
1381                 hrtime_t cached_stamp;
1382                 pathname_t rpn;
1383 
1384                 cached_stamp = vp->v_path_stamp;
1385                 (void) pn_set(&pn, vp->v_path);
1386                 mutex_exit(&vp->v_lock);
1387 


1388                 /* We should only cache absolute paths */
1389                 ASSERT(pn.pn_buf[0] == '/');
1390 
1391                 pn_alloc(&rpn);
1392                 if (vnode_valid_pn(vp, vrootp, &pn, &rpn, flags, cr) == 0) {
1393                         /* Return the result, if we're able. */
1394                         if (buflen > rpn.pn_pathlen) {
1395                                 bcopy(rpn.pn_path, buf, rpn.pn_pathlen + 1);






























1396                         } else {
1397                                 ret = ENAMETOOLONG;
1398                         }































1399                         pn_free(&pn);
1400                         pn_free(&rpn);
1401                         goto out;



1402                 }




1403                 pn_free(&rpn);
1404                 vn_clearpath(vp, cached_stamp);
1405         } else {
1406                 mutex_exit(&vp->v_lock);
1407         }

1408         pn_free(&pn);
1409 
1410         if (vp->v_type != VDIR) {
1411                 /*
1412                  * The reverse lookup tricks used by dirtopath aren't possible
1413                  * for non-directory entries.  The best which can be done is
1414                  * clearing any stale v_path so later lookups can potentially
1415                  * repopulate it with a valid path.





1416                  */
1417                 ret = ENOENT;























1418         } else {
1419                 ret = dirtopath(vrootp, vp, buf, buflen, flags, cr);



1420         }

1421 
1422 out:





1423         VN_RELE(vrootp);
1424         if (doclose) {
1425                 (void) VOP_CLOSE(vp, FREAD, 1, 0, cr, NULL);
1426                 VN_RELE(vp);
1427         }
1428 
1429         return (ret);
1430 }
1431 
1432 int
1433 vnodetopath(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, cred_t *cr)
1434 {
1435         return (vnodetopath_common(vrootp, vp, buf, buflen, cr, 0));
1436 }
1437 
1438 int
1439 dogetcwd(char *buf, size_t buflen)
1440 {
1441         int ret;
1442         vnode_t *vp;




   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.
   7  *
   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.
  12  *
  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]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright (c) 2015, Joyent, Inc. All rights reserved.
  25  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  26  */
  27 
  28 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  29 /*        All Rights Reserved   */
  30 
  31 /*
  32  * University Copyright- Copyright (c) 1982, 1986, 1988
  33  * The Regents of the University of California
  34  * All Rights Reserved
  35  *
  36  * University Acknowledgment- Portions of this document are derived from
  37  * software developed by the University of California, Berkeley, and its
  38  * contributors.
  39  */
  40 
  41 #include <sys/types.h>
  42 #include <sys/param.h>
  43 #include <sys/systm.h>
  44 #include <sys/cpuvar.h>


 962                         break;
 963                 VN_RELE(vp);
 964                 vp = cvp;
 965 
 966                 if (vn_ismntpt(vp) && traverse(&vp) != 0)
 967                         break;
 968 
 969                 if (vn_compare(vp, vrootp)) {
 970                         ret = path + (pn.pn_path - pn.pn_buf);
 971                         break;
 972                 }
 973         }
 974 
 975         VN_RELE(vp);
 976         pn_free(&pn);
 977 
 978         return (ret);
 979 }
 980 
 981 /*







































































































 982  * Given a directory, return the full, resolved path.  This looks up "..",
 983  * searches for the given vnode in the parent, appends the component, etc.  It
 984  * is used to implement vnodetopath() and getcwd() when the cached path fails.
 985  */
 986 static int
 987 dirtopath(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, int flags,
 988     cred_t *cr)
 989 {
 990         pathname_t pn, rpn, emptypn;
 991         vnode_t *cmpvp, *pvp = NULL;
 992         vnode_t *startvp = vp;
 993         int err = 0, vprivs;
 994         size_t complen;
 995         char *dbuf;
 996         dirent64_t *dp;
 997         char            *bufloc;
 998         size_t          dlen = DIRENT64_RECLEN(MAXPATHLEN);
 999         refstr_t        *mntpt;
1000 
1001         /* Operation only allowed on directories */
1002         ASSERT(vp->v_type == VDIR);
1003 
1004         /* We must have at least enough space for "/" */
1005         if (buflen < 2)
1006                 return (ENAMETOOLONG);
1007 
1008         /* Start at end of string with terminating null */
1009         bufloc = &buf[buflen - 1];
1010         *bufloc = '\0';
1011 
1012         pn_alloc(&pn);
1013         pn_alloc(&rpn);
1014         dbuf = kmem_alloc(dlen, KM_SLEEP);
1015         bzero(&emptypn, sizeof (emptypn));
1016 
1017         /*
1018          * Begin with an additional reference on vp.  This will be decremented
1019          * during the loop.
1020          */
1021         VN_HOLD(vp);
1022 
1023         for (;;) {



1024                 /*
1025                  * Return if we've reached the root.  If the buffer is empty,
1026                  * return '/'.  We explicitly don't use vn_compare(), since it
1027                  * compares the real vnodes.  A lofs mount of '/' would produce
1028                  * incorrect results otherwise.
1029                  */
1030                 if (VN_CMP(vrootp, vp)) {
1031                         if (*bufloc == '\0')
1032                                 *--bufloc = '/';
1033                         break;
1034                 }
1035 
1036                 /*
1037                  * If we've reached the VFS root, something has gone wrong.  We
1038                  * should have reached the root in the above check.  The only
1039                  * explantation is that 'vp' is not contained withing the given
1040                  * root, in which case we return EPERM.
1041                  */
1042                 if (VN_CMP(rootdir, vp)) {
1043                         err = EPERM;
1044                         goto out;
1045                 }
1046 
1047                 /*
1048                  * Shortcut: see if this vnode is a mountpoint.  If so,
1049                  * grab the path information from the vfs_t.
1050                  */
1051                 if (vp->v_flag & VROOT) {
1052 
1053                         mntpt = vfs_getmntpoint(vp->v_vfsp);
1054                         if ((err = pn_set(&pn, (char *)refstr_value(mntpt)))
1055                             == 0) {
1056                                 refstr_rele(mntpt);
1057                                 rpn.pn_path = rpn.pn_buf;
1058 
1059                                 /*
1060                                  * Ensure the mountpoint still exists.
1061                                  */
1062                                 VN_HOLD(vrootp);
1063                                 if (vrootp != rootdir)
1064                                         VN_HOLD(vrootp);
1065                                 if (lookuppnvp(&pn, &rpn, flags, NULL,
1066                                     &cmpvp, vrootp, vrootp, cr) == 0) {
1067 
1068                                         if (VN_CMP(vp, cmpvp)) {
1069                                                 VN_RELE(cmpvp);
1070 
1071                                                 complen = strlen(rpn.pn_path);
1072                                                 bufloc -= complen;
1073                                                 if (bufloc < buf) {
1074                                                         err = ERANGE;
1075                                                         goto out;
1076                                                 }
1077                                                 bcopy(rpn.pn_path, bufloc,
1078                                                     complen);
1079                                                 break;
1080                                         } else {
1081                                                 VN_RELE(cmpvp);
1082                                         }
1083                                 }
1084                         } else {
1085                                 refstr_rele(mntpt);
1086                         }
1087                 }
1088 
1089                 /*
1090                  * Shortcut: see if this vnode has correct v_path. If so,
1091                  * we have the work done.
1092                  */
1093                 mutex_enter(&vp->v_lock);
1094                 if (vp->v_path != NULL) {
1095 
1096                         if ((err = pn_set(&pn, vp->v_path)) == 0) {
1097                                 mutex_exit(&vp->v_lock);
1098                                 rpn.pn_path = rpn.pn_buf;
1099 
1100                                 /*
1101                                  * Ensure the v_path pointing to correct vnode
1102                                  */
1103                                 VN_HOLD(vrootp);
1104                                 if (vrootp != rootdir)
1105                                         VN_HOLD(vrootp);
1106                                 if (lookuppnvp(&pn, &rpn, flags, NULL,
1107                                     &cmpvp, vrootp, vrootp, cr) == 0) {
1108 
1109                                         if (VN_CMP(vp, cmpvp)) {
1110                                                 VN_RELE(cmpvp);
1111 
1112                                                 complen = strlen(rpn.pn_path);
1113                                                 bufloc -= complen;
1114                                                 if (bufloc < buf) {
1115                                                         err = ERANGE;
1116                                                         goto out;
1117                                                 }
1118                                                 bcopy(rpn.pn_path, bufloc,
1119                                                     complen);
1120                                                 break;
1121                                         } else {
1122                                                 VN_RELE(cmpvp);




1123                                         }
1124                                 }
1125                         } else {
1126                                 mutex_exit(&vp->v_lock);
1127                         }
1128                 } else {
1129                         mutex_exit(&vp->v_lock);
1130                 }
1131 
1132                 /*
1133                  * Shortcuts failed, search for this vnode in its parent.  If
1134                  * this is a mountpoint, then get the vnode underneath.
1135                  */
1136                 if (vp->v_flag & VROOT)
1137                         vp = vn_under(vp);
1138                 if ((err = VOP_LOOKUP(vp, "..", &pvp, &emptypn, 0, vrootp, cr,
1139                     NULL, NULL, NULL)) != 0)
1140                         goto out;
1141 
1142                 /*
1143                  * With extended attributes, it's possible for a directory to
1144                  * have a parent that is a regular file.  Check for that here.
1145                  */
1146                 if (pvp->v_type != VDIR) {
1147                         err = ENOTDIR;
1148                         goto out;
1149                 }
1150 
1151                 /*
1152                  * If this is true, something strange has happened.  This is
1153                  * only true if we are the root of a filesystem, which should
1154                  * have been caught by the check above.
1155                  */
1156                 if (VN_CMP(pvp, vp)) {
1157                         err = ENOENT;
1158                         goto out;
1159                 }
1160 
1161                 /*
1162                  * Check if we have read and search privilege so, that
1163                  * we can lookup the path in the directory
1164                  */
1165                 vprivs = (flags & LOOKUP_CHECKREAD) ? VREAD | VEXEC : VEXEC;
1166                 if ((err = VOP_ACCESS(pvp, vprivs, 0, cr, NULL)) != 0) {
1167                         goto out;
1168                 }
1169 
1170                 /*
1171                  * Try to obtain the path component from dnlc cache
1172                  * before searching through the directory.
1173                  */
1174                 if ((cmpvp = dnlc_reverse_lookup(vp, dbuf, dlen)) != NULL) {
1175                         /*
1176                          * If we got parent vnode as a result,
1177                          * then the answered path is correct.
1178                          */
1179                         if (VN_CMP(cmpvp, pvp)) {
1180                                 VN_RELE(cmpvp);
1181                                 complen = strlen(dbuf);
1182                                 bufloc -= complen;
1183                                 if (bufloc <= buf) {
1184                                         err = ENAMETOOLONG;
1185                                         goto out;
1186                                 }
1187                                 bcopy(dbuf, bufloc, complen);
1188 
1189                                 /* Prepend a slash to the current path */
1190                                 *--bufloc = '/';
1191 
1192                                 /* And continue with the next component */
1193                                 VN_RELE(vp);
1194                                 vp = pvp;
1195                                 pvp = NULL;
1196                                 continue;
1197                         } else {
1198                                 VN_RELE(cmpvp);
1199                         }
1200                 }
1201 
1202                 /*
1203                  * Search the parent directory for the entry corresponding to
1204                  * this vnode.
1205                  */
1206                 if ((err = dirfindvp(vrootp, pvp, vp, cr, dbuf, dlen, &dp))
1207                     != 0)
1208                         goto out;
1209                 complen = strlen(dp->d_name);
1210                 bufloc -= complen;
1211                 if (bufloc <= buf) {
1212                         err = ENAMETOOLONG;
1213                         goto out;
1214                 }
1215                 bcopy(dp->d_name, bufloc, complen);
1216 
1217                 /* Prepend a slash to the current path.  */
1218                 *--bufloc = '/';
1219 













1220                 /* And continue with the next component */
1221                 VN_RELE(vp);
1222                 vp = pvp;
1223                 pvp = NULL;
1224         }
1225 
1226         /*
1227          * Place the path at the beginning of the buffer.
1228          */
1229         if (bufloc != buf)
1230                 ovbcopy(bufloc, buf, buflen - (bufloc - buf));
1231 
1232 out:
1233         /*































1234          * If the error was ESTALE and the current directory to look in
1235          * was the root for this lookup, the root for a mounted file
1236          * system, or the starting directory for lookups, then
1237          * return ENOENT instead of ESTALE.  In this case, no recovery
1238          * is possible by the higher level.  If ESTALE was returned for
1239          * some intermediate directory along the path, then recovery
1240          * is potentially possible and retrying from the higher level
1241          * will either correct the situation by purging stale cache
1242          * entries or eventually get back to the point where no recovery
1243          * is possible.
1244          */
1245         if (err == ESTALE &&
1246             (VN_CMP(vp, vrootp) || (vp->v_flag & VROOT) || vp == startvp))
1247                 err = ENOENT;
1248 
1249         kmem_free(dbuf, dlen);
1250         VN_RELE(vp);
1251         if (pvp)
1252                 VN_RELE(pvp);
1253         pn_free(&pn);
1254         pn_free(&rpn);
1255 
1256         return (err);
1257 }
1258 
1259 /*
1260  * The additional flag, LOOKUP_CHECKREAD, is used to enforce artificial
1261  * constraints in order to be standards compliant.  For example, if we have
1262  * the cached path of '/foo/bar', and '/foo' has permissions 100 (execute
1263  * only), then we can legitimately look up the path to the current working
1264  * directory without needing read permission.  Existing standards tests,
1265  * however, assume that we are determining the path by repeatedly looking up
1266  * "..".  We need to keep this behavior in order to maintain backwards
1267  * compatibility.
1268  */
1269 static int
1270 vnodetopath_common(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen,
1271     cred_t *cr, int flags)
1272 {
1273         pathname_t pn, rpn;
1274         int ret, len;
1275         vnode_t *compvp, *pvp, *realvp;
1276         proc_t *p = curproc;
1277         char path[MAXNAMELEN];
1278         int doclose = 0;
1279 
1280         /*
1281          * If vrootp is NULL, get the root for curproc.  Callers with any other
1282          * requirements should pass in a different vrootp.
1283          */
1284         if (vrootp == NULL) {


1285                 mutex_enter(&p->p_lock);
1286                 if ((vrootp = PTOU(p)->u_rdir) == NULL)
1287                         vrootp = rootdir;
1288                 VN_HOLD(vrootp);
1289                 mutex_exit(&p->p_lock);
1290         } else {
1291                 VN_HOLD(vrootp);
1292         }
1293 
1294         /*
1295          * This is to get around an annoying artifact of the /proc filesystem,
1296          * which is the behavior of {cwd/root}.  Trying to resolve this path
1297          * will result in /proc/pid/cwd instead of whatever the real working
1298          * directory is.  We can't rely on VOP_REALVP(), since that will break
1299          * lofs.  The only difference between procfs and lofs is that opening
1300          * the file will return the underling vnode in the case of procfs.
1301          */
1302         if (vp->v_type == VDIR && VOP_REALVP(vp, &realvp, NULL) == 0 &&
1303             realvp != vp) {
1304                 VN_HOLD(vp);
1305                 if (VOP_OPEN(&vp, FREAD, cr, NULL) == 0)
1306                         doclose = 1;
1307                 else
1308                         VN_RELE(vp);
1309         }
1310 
1311         pn_alloc(&pn);
1312 
1313         /*
1314          * Check to see if we have a cached path in the vnode.
1315          */

1316         mutex_enter(&vp->v_lock);
1317         if (vp->v_path != NULL) {




1318                 (void) pn_set(&pn, vp->v_path);
1319                 mutex_exit(&vp->v_lock);
1320 
1321                 pn_alloc(&rpn);
1322 
1323                 /* We should only cache absolute paths */
1324                 ASSERT(pn.pn_buf[0] == '/');
1325 
1326                 /*
1327                  * If we are in a zone or a chroot environment, then we have to
1328                  * take additional steps, since the path to the root might not
1329                  * be readable with the current credentials, even though the
1330                  * process can legitmately access the file.  In this case, we
1331                  * do the following:
1332                  *
1333                  * lookuppnvp() with all privileges to get the resolved path.
1334                  * call localpath() to get the local portion of the path, and
1335                  * continue as normal.
1336                  *
1337                  * If the the conversion to a local path fails, then we continue
1338                  * as normal.  This is a heuristic to make process object file
1339                  * paths available from within a zone.  Because lofs doesn't
1340                  * support page operations, the vnode stored in the seg_t is
1341                  * actually the underlying real vnode, not the lofs node itself.
1342                  * Most of the time, the lofs path is the same as the underlying
1343                  * vnode (for example, /usr/lib/libc.so.1).
1344                  */
1345                 if (vrootp != rootdir) {
1346                         char *local = NULL;
1347                         VN_HOLD(rootdir);
1348                         if (lookuppnvp(&pn, &rpn, FOLLOW,
1349                             NULL, &compvp, rootdir, rootdir, kcred) == 0) {
1350                                 local = localpath(rpn.pn_path, vrootp,
1351                                     kcred);
1352                                 VN_RELE(compvp);
1353                         }
1354 
1355                         /*
1356                          * The original pn was changed through lookuppnvp().
1357                          * Set it to local for next validation attempt.
1358                          */
1359                         if (local) {
1360                                 (void) pn_set(&pn, local);
1361                         } else {
1362                                 goto notcached;
1363                         }
1364                 }
1365 
1366                 /*
1367                  * We should have a local path at this point, so start the
1368                  * search from the root of the current process.
1369                  */
1370                 VN_HOLD(vrootp);
1371                 if (vrootp != rootdir)
1372                         VN_HOLD(vrootp);
1373                 ret = lookuppnvp(&pn, &rpn, FOLLOW | flags, NULL,
1374                     &compvp, vrootp, vrootp, cr);
1375                 if (ret == 0) {
1376                         /*
1377                          * Check to see if the returned vnode is the same as
1378                          * the one we expect.  If not, give up.
1379                          */
1380                         if (!vn_compare(vp, compvp) &&
1381                             !vnode_match(vp, compvp, cr)) {
1382                                 VN_RELE(compvp);
1383                                 goto notcached;
1384                         }
1385 
1386                         VN_RELE(compvp);
1387 
1388                         /*
1389                          * Return the result.
1390                          */
1391                         if (buflen <= rpn.pn_pathlen)
1392                                 goto notcached;
1393 
1394                         bcopy(rpn.pn_path, buf, rpn.pn_pathlen + 1);
1395                         pn_free(&pn);
1396                         pn_free(&rpn);
1397                         VN_RELE(vrootp);
1398                         if (doclose) {
1399                                 (void) VOP_CLOSE(vp, FREAD, 1, 0, cr, NULL);
1400                                 VN_RELE(vp);
1401                         }
1402                         return (0);
1403                 }
1404 
1405 notcached:
1406                 pn_free(&rpn);

1407         } else {
1408                 mutex_exit(&vp->v_lock);
1409         }
1410 
1411         pn_free(&pn);
1412 
1413         if (PROC_IS_BRANDED(curproc)) {
1414                 /*
1415                  * If v_path doesn't work out and we're in a branded zone,
1416                  * we're not going to bother doing more work here:  because
1417                  * directories from the global can be lofs mounted into odd
1418                  * locations (e.g., /native in an lx zone), it is likely that
1419                  * the DNLC reverse lookup will yield nothing.  Indeed, the
1420                  * only certainty is that the DNLC reverse lookup will be
1421                  * exceedingly painful; we save ourselves the substantial
1422                  * grief of scanning the entire DNLC and kick out with ENOENT
1423                  * in this case.
1424                  */
1425                 ret = ENOENT;
1426         } else if (vp->v_type != VDIR) {
1427                 /*
1428                  * If we don't have a directory, try to find it in the dnlc via
1429                  * reverse lookup.  Once this is found, we can use the regular
1430                  * directory search to find the full path.
1431                  */
1432                 if ((pvp = dnlc_reverse_lookup(vp, path, MAXNAMELEN)) != NULL) {
1433                         /*
1434                          * Check if we have read privilege so, that
1435                          * we can lookup the path in the directory
1436                          */
1437                         ret = 0;
1438                         if ((flags & LOOKUP_CHECKREAD)) {
1439                                 ret = VOP_ACCESS(pvp, VREAD, 0, cr, NULL);
1440                         }
1441                         if (ret == 0) {
1442                                 ret = dirtopath(vrootp, pvp, buf, buflen,
1443                                     flags, cr);
1444                         }
1445                         if (ret == 0) {
1446                                 len = strlen(buf);
1447                                 if (len + strlen(path) + 1 >= buflen) {
1448                                         ret = ENAMETOOLONG;
1449                                 } else {
1450                                         if (buf[len - 1] != '/')
1451                                                 buf[len++] = '/';
1452                                         bcopy(path, buf + len,
1453                                             strlen(path) + 1);
1454                                 }
1455                         }
1456 
1457                         VN_RELE(pvp);
1458                 } else
1459                         ret = ENOENT;
1460         } else
1461                 ret = dirtopath(vrootp, vp, buf, buflen, flags, cr);
1462 
1463         VN_RELE(vrootp);
1464         if (doclose) {
1465                 (void) VOP_CLOSE(vp, FREAD, 1, 0, cr, NULL);
1466                 VN_RELE(vp);
1467         }
1468 
1469         return (ret);
1470 }
1471 
1472 int
1473 vnodetopath(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, cred_t *cr)
1474 {
1475         return (vnodetopath_common(vrootp, vp, buf, buflen, cr, 0));
1476 }
1477 
1478 int
1479 dogetcwd(char *buf, size_t buflen)
1480 {
1481         int ret;
1482         vnode_t *vp;