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;
|