1331722Seadler/* 223661Speter * Copyright (c) 1989, 1991, 1993, 1995 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 91573Srgrimes * notice, this list of conditions and the following disclaimer. 101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111573Srgrimes * notice, this list of conditions and the following disclaimer in the 121573Srgrimes * documentation and/or other materials provided with the distribution. 131573Srgrimes * 4. Neither the name of the University nor the names of its contributors 141573Srgrimes * may be used to endorse or promote products derived from this software 151573Srgrimes * without specific prior written permission. 161573Srgrimes * 171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271573Srgrimes * SUCH DAMAGE. 281573Srgrimes */ 291573Srgrimes 301573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 3123661Speterstatic char sccsid[] = "@(#)getcwd.c 8.5 (Berkeley) 2/7/95"; 321573Srgrimes#endif /* LIBC_SCCS and not lint */ 3390041Sobrien#include <sys/cdefs.h> 3490041Sobrien__FBSDID("$FreeBSD$"); 351573Srgrimes 3671579Sdeischen#include "namespace.h" 371573Srgrimes#include <sys/param.h> 381573Srgrimes#include <sys/stat.h> 391573Srgrimes 4023661Speter#include <dirent.h> 411573Srgrimes#include <errno.h> 4223661Speter#include <fcntl.h> 431573Srgrimes#include <stdio.h> 441573Srgrimes#include <stdlib.h> 451573Srgrimes#include <string.h> 461573Srgrimes#include <unistd.h> 4771579Sdeischen#include "un-namespace.h" 481573Srgrimes 49235647Sgleb#include "gen-private.h" 50235647Sgleb 511573Srgrimes#define ISDOT(dp) \ 521573Srgrimes (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ 5317141Sjkh (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) 541573Srgrimes 55109039Stjrextern int __getcwd(char *, size_t); 56109039Stjr 571573Srgrimeschar * 58288029Srodrigcgetcwd(char *pt, size_t size) 591573Srgrimes{ 6090041Sobrien struct dirent *dp; 6190041Sobrien DIR *dir = NULL; 6290041Sobrien dev_t dev; 6390041Sobrien ino_t ino; 6490041Sobrien int first; 65198053Sjilles char *bpt; 661573Srgrimes struct stat s; 671573Srgrimes dev_t root_dev; 681573Srgrimes ino_t root_ino; 69198053Sjilles size_t ptsize; 701573Srgrimes int save_errno; 71198053Sjilles char *ept, c; 72198053Sjilles int fd; 731573Srgrimes 741573Srgrimes /* 751573Srgrimes * If no buffer specified by the user, allocate one as necessary. 761573Srgrimes * If a buffer is specified, the size has to be non-zero. The path 771573Srgrimes * is built from the end of the buffer backwards. 781573Srgrimes */ 791573Srgrimes if (pt) { 801573Srgrimes ptsize = 0; 811573Srgrimes if (!size) { 821573Srgrimes errno = EINVAL; 831573Srgrimes return (NULL); 841573Srgrimes } 855072Sbde if (size == 1) { 865072Sbde errno = ERANGE; 875072Sbde return (NULL); 885072Sbde } 891573Srgrimes ept = pt + size; 901573Srgrimes } else { 91150172Sache if ((pt = malloc(ptsize = PATH_MAX)) == NULL) 921573Srgrimes return (NULL); 931573Srgrimes ept = pt + ptsize; 941573Srgrimes } 9565468Speter if (__getcwd(pt, ept - pt) == 0) { 9665468Speter if (*pt != '/') { 9765468Speter bpt = pt; 9865468Speter ept = pt + strlen(pt) - 1; 9965468Speter while (bpt < ept) { 10065468Speter c = *bpt; 10165468Speter *bpt++ = *ept; 10265468Speter *ept-- = c; 10329476Sphk } 10429392Sphk } 10565468Speter return (pt); 10629392Sphk } 1071573Srgrimes bpt = ept - 1; 1081573Srgrimes *bpt = '\0'; 1091573Srgrimes 1101573Srgrimes /* Save root values, so know when to stop. */ 1111573Srgrimes if (stat("/", &s)) 1121573Srgrimes goto err; 1131573Srgrimes root_dev = s.st_dev; 1141573Srgrimes root_ino = s.st_ino; 1151573Srgrimes 1161573Srgrimes errno = 0; /* XXX readdir has no error return. */ 1171573Srgrimes 1181573Srgrimes for (first = 1;; first = 0) { 1191573Srgrimes /* Stat the current level. */ 120235647Sgleb if (dir != NULL ? _fstat(_dirfd(dir), &s) : lstat(".", &s)) 1211573Srgrimes goto err; 1221573Srgrimes 1231573Srgrimes /* Save current node values. */ 1241573Srgrimes ino = s.st_ino; 1251573Srgrimes dev = s.st_dev; 1261573Srgrimes 1271573Srgrimes /* Check for reaching root. */ 1281573Srgrimes if (root_dev == dev && root_ino == ino) { 1291573Srgrimes *--bpt = '/'; 1301573Srgrimes /* 1311573Srgrimes * It's unclear that it's a requirement to copy the 1321573Srgrimes * path to the beginning of the buffer, but it's always 1331573Srgrimes * been that way and stuff would probably break. 1341573Srgrimes */ 1359272Shsu bcopy(bpt, pt, ept - bpt); 136198053Sjilles if (dir) 137198053Sjilles (void) closedir(dir); 1381573Srgrimes return (pt); 1391573Srgrimes } 1401573Srgrimes 1411573Srgrimes /* Open and stat parent directory. */ 142235647Sgleb fd = _openat(dir != NULL ? _dirfd(dir) : AT_FDCWD, 143241046Sjilles "..", O_RDONLY | O_CLOEXEC); 144198053Sjilles if (fd == -1) 1451573Srgrimes goto err; 146198053Sjilles if (dir) 147198053Sjilles (void) closedir(dir); 148235647Sgleb if (!(dir = fdopendir(fd)) || _fstat(_dirfd(dir), &s)) { 149198053Sjilles _close(fd); 150198053Sjilles goto err; 151198053Sjilles } 1521573Srgrimes 1531573Srgrimes /* 1541573Srgrimes * If it's a mount point, have to stat each element because 1551573Srgrimes * the inode number in the directory is for the entry in the 1561573Srgrimes * parent directory, not the inode number of the mounted file. 1571573Srgrimes */ 1581573Srgrimes save_errno = 0; 1591573Srgrimes if (s.st_dev == dev) { 1601573Srgrimes for (;;) { 1611573Srgrimes if (!(dp = readdir(dir))) 1621573Srgrimes goto notfound; 1631573Srgrimes if (dp->d_fileno == ino) 1641573Srgrimes break; 1651573Srgrimes } 1661573Srgrimes } else 1671573Srgrimes for (;;) { 1681573Srgrimes if (!(dp = readdir(dir))) 1691573Srgrimes goto notfound; 1701573Srgrimes if (ISDOT(dp)) 1711573Srgrimes continue; 1721573Srgrimes 1731573Srgrimes /* Save the first error for later. */ 174235647Sgleb if (fstatat(_dirfd(dir), dp->d_name, &s, 175198053Sjilles AT_SYMLINK_NOFOLLOW)) { 1761573Srgrimes if (!save_errno) 1771573Srgrimes save_errno = errno; 1781573Srgrimes errno = 0; 1791573Srgrimes continue; 1801573Srgrimes } 1811573Srgrimes if (s.st_dev == dev && s.st_ino == ino) 1821573Srgrimes break; 1831573Srgrimes } 1841573Srgrimes 1851573Srgrimes /* 1861573Srgrimes * Check for length of the current name, preceding slash, 1871573Srgrimes * leading slash. 1881573Srgrimes */ 189150297Sache while (bpt - pt < dp->d_namlen + (first ? 1 : 2)) { 1901573Srgrimes size_t len, off; 1911573Srgrimes 1921573Srgrimes if (!ptsize) { 1931573Srgrimes errno = ERANGE; 1941573Srgrimes goto err; 1951573Srgrimes } 1961573Srgrimes off = bpt - pt; 1971573Srgrimes len = ept - bpt; 198109040Stjr if ((pt = reallocf(pt, ptsize *= 2)) == NULL) 1991573Srgrimes goto err; 2001573Srgrimes bpt = pt + off; 2011573Srgrimes ept = pt + ptsize; 2029272Shsu bcopy(bpt, ept - len, len); 2031573Srgrimes bpt = ept - len; 2041573Srgrimes } 2051573Srgrimes if (!first) 2061573Srgrimes *--bpt = '/'; 2071573Srgrimes bpt -= dp->d_namlen; 2081573Srgrimes bcopy(dp->d_name, bpt, dp->d_namlen); 2091573Srgrimes } 2101573Srgrimes 2111573Srgrimesnotfound: 2121573Srgrimes /* 2131573Srgrimes * If readdir set errno, use it, not any saved error; otherwise, 2141573Srgrimes * didn't find the current directory in its parent directory, set 2151573Srgrimes * errno to ENOENT. 2161573Srgrimes */ 2171573Srgrimes if (!errno) 2181573Srgrimes errno = save_errno ? save_errno : ENOENT; 2191573Srgrimes /* FALLTHROUGH */ 2201573Srgrimeserr: 22132530Smckay save_errno = errno; 22232530Smckay 2231573Srgrimes if (ptsize) 2241573Srgrimes free(pt); 22528235Sdg if (dir) 22628235Sdg (void) closedir(dir); 22732530Smckay 22832530Smckay errno = save_errno; 2291573Srgrimes return (NULL); 2301573Srgrimes} 231