1 /* $NetBSD: vfs_getcwd.c,v 1.26 2004/09/17 14:11:25 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Bill Sommerfeld. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: vfs_getcwd.c,v 1.26 2004/09/17 14:11:25 skrll Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/namei.h> 45 #include <sys/filedesc.h> 46 #include <sys/kernel.h> 47 #include <sys/file.h> 48 #include <sys/stat.h> 49 #include <sys/vnode.h> 50 #include <sys/mount.h> 51 #include <sys/proc.h> 52 #include <sys/uio.h> 53 #include <sys/malloc.h> 54 #include <sys/dirent.h> 55 #include <ufs/ufs/dir.h> /* XXX only for DIRBLKSIZ */ 56 57 #include <sys/sa.h> 58 #include <sys/syscallargs.h> 59 60 static int 61 getcwd_scandir(struct vnode **, struct vnode **, 62 char **, char *, struct proc *); 63 static int 64 getcwd_getcache(struct vnode **, struct vnode **, 65 char **, char *); 66 67 #define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN + 1) + 4) 68 69 /* 70 * Vnode variable naming conventions in this file: 71 * 72 * rvp: the current root we're aiming towards. 73 * lvp, *lvpp: the "lower" vnode 74 * uvp, *uvpp: the "upper" vnode. 75 * 76 * Since all the vnodes we're dealing with are directories, and the 77 * lookups are going *up* in the filesystem rather than *down*, the 78 * usual "pvp" (parent) or "dvp" (directory) naming conventions are 79 * too confusing. 80 */ 81 82 /* 83 * XXX Will infinite loop in certain cases if a directory read reliably 84 * returns EINVAL on last block. 85 * XXX is EINVAL the right thing to return if a directory is malformed? 86 */ 87 88 /* 89 * XXX Untested vs. mount -o union; probably does the wrong thing. 90 */ 91 92 /* 93 * Find parent vnode of *lvpp, return in *uvpp 94 * 95 * If we care about the name, scan it looking for name of directory 96 * entry pointing at lvp. 97 * 98 * Place the name in the buffer which starts at bufp, immediately 99 * before *bpp, and move bpp backwards to point at the start of it. 100 * 101 * On entry, *lvpp is a locked vnode reference; on exit, it is vput and NULL'ed 102 * On exit, *uvpp is either NULL or is a locked vnode reference. 103 */ 104 static int 105 getcwd_scandir(lvpp, uvpp, bpp, bufp, p) 106 struct vnode **lvpp; 107 struct vnode **uvpp; 108 char **bpp; 109 char *bufp; 110 struct proc *p; 111 { 112 int error = 0; 113 int eofflag; 114 off_t off; 115 int tries; 116 struct uio uio; 117 struct iovec iov; 118 char *dirbuf = NULL; 119 int dirbuflen; 120 ino_t fileno; 121 struct vattr va; 122 struct vnode *uvp = NULL; 123 struct vnode *lvp = *lvpp; 124 struct componentname cn; 125 int len, reclen; 126 tries = 0; 127 128 /* 129 * If we want the filename, get some info we need while the 130 * current directory is still locked. 131 */ 132 if (bufp != NULL) { 133 error = VOP_GETATTR(lvp, &va, p->p_ucred, p); 134 if (error) { 135 vput(lvp); 136 *lvpp = NULL; 137 *uvpp = NULL; 138 return error; 139 } 140 } 141 142 /* 143 * Ok, we have to do it the hard way.. 144 * Next, get parent vnode using lookup of .. 145 */ 146 cn.cn_nameiop = LOOKUP; 147 cn.cn_flags = ISLASTCN | ISDOTDOT | RDONLY; 148 cn.cn_proc = p; 149 cn.cn_cred = p->p_ucred; 150 cn.cn_pnbuf = NULL; 151 cn.cn_nameptr = ".."; 152 cn.cn_namelen = 2; 153 cn.cn_hash = 0; 154 cn.cn_consume = 0; 155 156 /* 157 * At this point, lvp is locked and will be unlocked by the lookup. 158 * On successful return, *uvpp will be locked 159 */ 160 error = VOP_LOOKUP(lvp, uvpp, &cn); 161 if (error) { 162 vput(lvp); 163 *lvpp = NULL; 164 *uvpp = NULL; 165 return error; 166 } 167 uvp = *uvpp; 168 169 /* If we don't care about the pathname, we're done */ 170 if (bufp == NULL) { 171 vrele(lvp); 172 *lvpp = NULL; 173 return 0; 174 } 175 176 fileno = va.va_fileid; 177 178 dirbuflen = DIRBLKSIZ; 179 if (dirbuflen < va.va_blocksize) 180 dirbuflen = va.va_blocksize; 181 dirbuf = (char *)malloc(dirbuflen, M_TEMP, M_WAITOK); 182 183 #if 0 184 unionread: 185 #endif 186 off = 0; 187 do { 188 /* call VOP_READDIR of parent */ 189 iov.iov_base = dirbuf; 190 iov.iov_len = dirbuflen; 191 192 uio.uio_iov = &iov; 193 uio.uio_iovcnt = 1; 194 uio.uio_offset = off; 195 uio.uio_resid = dirbuflen; 196 uio.uio_segflg = UIO_SYSSPACE; 197 uio.uio_rw = UIO_READ; 198 uio.uio_procp = NULL; 199 200 eofflag = 0; 201 202 error = VOP_READDIR(uvp, &uio, p->p_ucred, &eofflag, 0, 0); 203 204 off = uio.uio_offset; 205 206 /* 207 * Try again if NFS tosses its cookies. 208 * XXX this can still loop forever if the directory is busted 209 * such that the second or subsequent page of it always 210 * returns EINVAL 211 */ 212 if ((error == EINVAL) && (tries < 3)) { 213 off = 0; 214 tries++; 215 continue; /* once more, with feeling */ 216 } 217 218 if (!error) { 219 char *cpos; 220 struct dirent *dp; 221 222 cpos = dirbuf; 223 tries = 0; 224 225 /* scan directory page looking for matching vnode */ 226 for (len = (dirbuflen - uio.uio_resid); len > 0; 227 len -= reclen) { 228 dp = (struct dirent *) cpos; 229 reclen = dp->d_reclen; 230 231 /* check for malformed directory.. */ 232 if (reclen < DIRENT_MINSIZE) { 233 error = EINVAL; 234 goto out; 235 } 236 /* 237 * XXX should perhaps do VOP_LOOKUP to 238 * check that we got back to the right place, 239 * but getting the locking games for that 240 * right would be heinous. 241 */ 242 if ((dp->d_type != DT_WHT) && 243 (dp->d_fileno == fileno)) { 244 char *bp = *bpp; 245 246 bp -= dp->d_namlen; 247 if (bp <= bufp) { 248 error = ERANGE; 249 goto out; 250 } 251 memcpy(bp, dp->d_name, dp->d_namlen); 252 error = 0; 253 *bpp = bp; 254 goto out; 255 } 256 cpos += reclen; 257 } 258 } else 259 goto out; 260 } while (!eofflag); 261 #if 0 262 /* 263 * Deal with mount -o union, which unions only the 264 * root directory of the mount. 265 */ 266 if ((uvp->v_flag & VROOT) && 267 (uvp->v_mount->mnt_flag & MNT_UNION)) { 268 struct vnode *tvp = uvp; 269 270 uvp = uvp->v_mount->mnt_vnodecovered; 271 vput(tvp); 272 VREF(uvp); 273 *uvpp = uvp; 274 error = vn_lock(uvp, LK_EXCLUSIVE | LK_RETRY); 275 if (error != 0) { 276 vrele(uvp); 277 *uvpp = uvp = NULL; 278 goto out; 279 } 280 goto unionread; 281 } 282 #endif 283 error = ENOENT; 284 285 out: 286 vrele(lvp); 287 *lvpp = NULL; 288 free(dirbuf, M_TEMP); 289 return error; 290 } 291 292 /* 293 * Look in the vnode-to-name reverse cache to see if 294 * we can find things the easy way. 295 * 296 * XXX vget failure path is untested. 297 * 298 * On entry, *lvpp is a locked vnode reference. 299 * On exit, one of the following is the case: 300 * 0) Both *lvpp and *uvpp are NULL and failure is returned. 301 * 1) *uvpp is NULL, *lvpp remains locked and -1 is returned (cache miss) 302 * 2) *uvpp is a locked vnode reference, *lvpp is vput and NULL'ed 303 * and 0 is returned (cache hit) 304 */ 305 306 static int 307 getcwd_getcache(lvpp, uvpp, bpp, bufp) 308 struct vnode **lvpp, **uvpp; 309 char **bpp; 310 char *bufp; 311 { 312 struct vnode *lvp, *uvp = NULL; 313 char *obp = *bpp; 314 int error; 315 316 lvp = *lvpp; 317 318 /* 319 * This returns 0 on a cache hit, -1 on a clean cache miss, 320 * or an errno on other failure. 321 */ 322 error = cache_revlookup(lvp, uvpp, bpp, bufp); 323 if (error) { 324 if (error != -1) { 325 vput(lvp); 326 *lvpp = NULL; 327 *uvpp = NULL; 328 } 329 return error; 330 } 331 uvp = *uvpp; 332 333 /* 334 * Since we're going up, we have to release the current lock 335 * before we take the parent lock. 336 */ 337 338 VOP_UNLOCK(lvp, 0); 339 340 error = vget(uvp, LK_EXCLUSIVE | LK_RETRY); 341 /* 342 * Verify that vget succeeded while we were waiting for the 343 * lock. 344 */ 345 if (error) { 346 /* 347 * Oops, we missed. If the vget failed try to get our 348 * lock back; if that works, rewind the `bp' and tell 349 * caller to try things the hard way, otherwise give 350 * up. 351 */ 352 *uvpp = NULL; 353 error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY); 354 if (error == 0) { 355 *bpp = obp; 356 return -1; 357 } 358 } 359 vrele(lvp); 360 *lvpp = NULL; 361 362 return error; 363 } 364 365 /* 366 * common routine shared by sys___getcwd() and vn_isunder() 367 */ 368 369 int 370 getcwd_common(lvp, rvp, bpp, bufp, limit, flags, p) 371 struct vnode *lvp; 372 struct vnode *rvp; 373 char **bpp; 374 char *bufp; 375 int limit; 376 int flags; 377 struct proc *p; 378 { 379 struct cwdinfo *cwdi = p->p_cwdi; 380 struct vnode *uvp = NULL; 381 char *bp = NULL; 382 int error; 383 int perms = VEXEC; 384 385 if (rvp == NULL) { 386 rvp = cwdi->cwdi_rdir; 387 if (rvp == NULL) 388 rvp = rootvnode; 389 } 390 391 VREF(rvp); 392 VREF(lvp); 393 394 /* 395 * Error handling invariant: 396 * Before a `goto out': 397 * lvp is either NULL, or locked and held. 398 * uvp is either NULL, or locked and held. 399 */ 400 401 error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY); 402 if (error) { 403 vrele(lvp); 404 lvp = NULL; 405 goto out; 406 } 407 if (bufp) 408 bp = *bpp; 409 /* 410 * this loop will terminate when one of the following happens: 411 * - we hit the root 412 * - getdirentries or lookup fails 413 * - we run out of space in the buffer. 414 */ 415 if (lvp == rvp) { 416 if (bp) 417 *(--bp) = '/'; 418 goto out; 419 } 420 do { 421 if (lvp->v_type != VDIR) { 422 error = ENOTDIR; 423 goto out; 424 } 425 426 /* 427 * access check here is optional, depending on 428 * whether or not caller cares. 429 */ 430 if (flags & GETCWD_CHECK_ACCESS) { 431 error = VOP_ACCESS(lvp, perms, p->p_ucred, p); 432 if (error) 433 goto out; 434 perms = VEXEC|VREAD; 435 } 436 437 /* 438 * step up if we're a covered vnode.. 439 */ 440 while (lvp->v_flag & VROOT) { 441 struct vnode *tvp; 442 443 if (lvp == rvp) 444 goto out; 445 446 tvp = lvp; 447 lvp = lvp->v_mount->mnt_vnodecovered; 448 vput(tvp); 449 /* 450 * hodie natus est radici frater 451 */ 452 if (lvp == NULL) { 453 error = ENOENT; 454 goto out; 455 } 456 VREF(lvp); 457 error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY); 458 if (error != 0) { 459 vrele(lvp); 460 lvp = NULL; 461 goto out; 462 } 463 } 464 /* 465 * Look in the name cache; if that fails, look in the 466 * directory.. 467 */ 468 error = getcwd_getcache(&lvp, &uvp, &bp, bufp); 469 if (error == -1) 470 error = getcwd_scandir(&lvp, &uvp, &bp, bufp, p); 471 if (error) 472 goto out; 473 #if DIAGNOSTIC 474 if (lvp != NULL) 475 panic("getcwd: oops, forgot to null lvp"); 476 if (bufp && (bp <= bufp)) { 477 panic("getcwd: oops, went back too far"); 478 } 479 #endif 480 if (bp) 481 *(--bp) = '/'; 482 lvp = uvp; 483 uvp = NULL; 484 limit--; 485 } while ((lvp != rvp) && (limit > 0)); 486 487 out: 488 if (bpp) 489 *bpp = bp; 490 if (uvp) 491 vput(uvp); 492 if (lvp) 493 vput(lvp); 494 vrele(rvp); 495 return error; 496 } 497 498 /* 499 * Check if one directory can be found inside another in the directory 500 * hierarchy. 501 * 502 * Intended to be used in chroot, chdir, fchdir, etc., to ensure that 503 * chroot() actually means something. 504 */ 505 int 506 vn_isunder(lvp, rvp, p) 507 struct vnode *lvp; 508 struct vnode *rvp; 509 struct proc *p; 510 { 511 int error; 512 513 error = getcwd_common(lvp, rvp, NULL, NULL, MAXPATHLEN / 2, 0, p); 514 515 if (!error) 516 return 1; 517 else 518 return 0; 519 } 520 521 /* 522 * Returns true if proc p1's root directory equal to or under p2's 523 * root directory. 524 * 525 * Intended to be used from ptrace/procfs sorts of things. 526 */ 527 528 int 529 proc_isunder(p1, p2) 530 struct proc *p1; 531 struct proc *p2; 532 { 533 struct vnode *r1 = p1->p_cwdi->cwdi_rdir; 534 struct vnode *r2 = p2->p_cwdi->cwdi_rdir; 535 536 if (r1 == NULL) 537 return (r2 == NULL); 538 else if (r2 == NULL) 539 return 1; 540 else 541 return vn_isunder(r1, r2, p2); 542 } 543 544 /* 545 * Find pathname of process's current directory. 546 * 547 * Use vfs vnode-to-name reverse cache; if that fails, fall back 548 * to reading directory contents. 549 */ 550 551 int 552 sys___getcwd(l, v, retval) 553 struct lwp *l; 554 void *v; 555 register_t *retval; 556 { 557 struct sys___getcwd_args /* { 558 syscallarg(char *) bufp; 559 syscallarg(size_t) length; 560 } */ *uap = v; 561 562 int error; 563 char *path; 564 char *bp, *bend; 565 int len = SCARG(uap, length); 566 int lenused; 567 568 if (len > MAXPATHLEN * 4) 569 len = MAXPATHLEN * 4; 570 else if (len < 2) 571 return ERANGE; 572 573 path = (char *)malloc(len, M_TEMP, M_WAITOK); 574 if (!path) 575 return ENOMEM; 576 577 bp = &path[len]; 578 bend = bp; 579 *(--bp) = '\0'; 580 581 /* 582 * 5th argument here is "max number of vnodes to traverse". 583 * Since each entry takes up at least 2 bytes in the output buffer, 584 * limit it to N/2 vnodes for an N byte buffer. 585 */ 586 error = getcwd_common(l->l_proc->p_cwdi->cwdi_cdir, NULL, &bp, path, 587 len / 2, GETCWD_CHECK_ACCESS, l->l_proc); 588 589 if (error) 590 goto out; 591 lenused = bend - bp; 592 *retval = lenused; 593 /* put the result into user buffer */ 594 error = copyout(bp, SCARG(uap, bufp), lenused); 595 596 out: 597 free(path, M_TEMP); 598 return error; 599 } 600