121345Sdist /* 237209Sbostic * Copyright (c) 1989 The Regents of the University of California. 337209Sbostic * All rights reserved. 437209Sbostic * 537209Sbostic * Redistribution and use in source and binary forms are permitted 637209Sbostic * provided that the above copyright notice and this paragraph are 737209Sbostic * duplicated in all such forms and that any documentation, 837209Sbostic * advertising materials, and other materials related to such 937209Sbostic * distribution and use acknowledge that the software was developed 1037209Sbostic * by the University of California, Berkeley. The name of the 1137209Sbostic * University may not be used to endorse or promote products derived 1237209Sbostic * from this software without specific prior written permission. 1337209Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437209Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537209Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621345Sdist */ 179986Ssam 1826565Sdonn #if defined(LIBC_SCCS) && !defined(lint) 19*42396Sbostic static char sccsid[] = "@(#)getcwd.c 5.7 (Berkeley) 05/27/90"; 2037209Sbostic #endif /* LIBC_SCCS and not lint */ 2121345Sdist 2210088Ssam #include <sys/param.h> 2310088Ssam #include <sys/stat.h> 2437209Sbostic #include <dirent.h> 25*42396Sbostic #include <string.h> 269986Ssam 27*42396Sbostic #define ISDOT(dp) \ 28*42396Sbostic (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ 29*42396Sbostic dp->d_name[1] == '.' && dp->d_name[2] == '\0')) 30*42396Sbostic 319986Ssam char * 3237209Sbostic getwd(store) 3337209Sbostic char *store; 349986Ssam { 3537209Sbostic extern int errno; 36*42396Sbostic register struct dirent *dp; 3737209Sbostic register DIR *dir; 38*42396Sbostic register ino_t ino; 39*42396Sbostic register char *pp, *pu; 4037209Sbostic register int first; 41*42396Sbostic struct stat s; 42*42396Sbostic dev_t root_dev, dev; 4337209Sbostic ino_t root_ino; 4440556Skarels int save_errno, found; 45*42396Sbostic char path[MAXPATHLEN], up[MAXPATHLEN], *file; 469986Ssam 47*42396Sbostic /* save root values */ 4840556Skarels if (stat("/", &s)) { 4940556Skarels file = "/"; 5037209Sbostic goto err; 5140556Skarels } 5237209Sbostic root_dev = s.st_dev; 5337209Sbostic root_ino = s.st_ino; 54*42396Sbostic 55*42396Sbostic /* init path pointer; built from the end of the buffer */ 5637209Sbostic pp = path + sizeof(path) - 1; 5737209Sbostic *pp = '\0'; 58*42396Sbostic 59*42396Sbostic /* special case first stat, it's ".", not ".." */ 60*42396Sbostic up[0] = '.'; 61*42396Sbostic up[1] = '\0'; 62*42396Sbostic 6337209Sbostic for (pu = up, first = 1;; first = 0) { 64*42396Sbostic /* stat current level */ 65*42396Sbostic if (lstat(up, &s)) { 66*42396Sbostic file = up; 67*42396Sbostic goto err; 68*42396Sbostic } 69*42396Sbostic 70*42396Sbostic /* save current node values */ 71*42396Sbostic ino = s.st_ino; 72*42396Sbostic dev = s.st_dev; 73*42396Sbostic 74*42396Sbostic /* check for root */ 75*42396Sbostic if (root_dev == dev && root_ino == ino) { 7637209Sbostic *store = '/'; 7740556Skarels (void) strcpy(store + 1, pp); 7840556Skarels return (store); 7910155Ssam } 80*42396Sbostic 8137209Sbostic *pu++ = '.'; 8237209Sbostic *pu++ = '.'; 8337209Sbostic *pu = '\0'; 84*42396Sbostic 85*42396Sbostic /* open and stat parent */ 86*42396Sbostic if (!(dir = opendir(up)) || fstat(dirfd(dir), &s)) { 8740556Skarels file = up; 8840556Skarels goto err; 8937209Sbostic } 90*42396Sbostic found = save_errno = 0; 91*42396Sbostic 9237209Sbostic *pu++ = '/'; 93*42396Sbostic 94*42396Sbostic /* 95*42396Sbostic * if it's a mount point you have to stat each element because 96*42396Sbostic * the inode number in the directory is for the entry in the 97*42396Sbostic * parent directory, not the inode number of the mounted file. 98*42396Sbostic */ 99*42396Sbostic if (s.st_dev == dev) { 100*42396Sbostic while (dp = readdir(dir)) 101*42396Sbostic if (dp->d_fileno == ino) 102*42396Sbostic goto hit; 103*42396Sbostic } else { 104*42396Sbostic while (dp = readdir(dir)) { 105*42396Sbostic if (ISDOT(dp)) 106*42396Sbostic continue; 107*42396Sbostic bcopy(dp->d_name, pu, dp->d_namlen + 1); 108*42396Sbostic if (lstat(up, &s)) { 109*42396Sbostic file = dp->d_name; 110*42396Sbostic save_errno = errno; 111*42396Sbostic errno = 0; 112*42396Sbostic continue; 113*42396Sbostic } 114*42396Sbostic if (s.st_dev == dev && s.st_ino == ino) { 115*42396Sbostic hit: if (!first) 116*42396Sbostic *--pp = '/'; 117*42396Sbostic pp -= dp->d_namlen; 118*42396Sbostic bcopy(dp->d_name, pp, dp->d_namlen); 119*42396Sbostic found = 1; 120*42396Sbostic break; 121*42396Sbostic } 122*42396Sbostic } 123*42396Sbostic if (errno) { 124*42396Sbostic file = up; 12540556Skarels save_errno = errno; 12640556Skarels } 12737209Sbostic } 128*42396Sbostic (void) closedir(dir); 129*42396Sbostic 13037209Sbostic *pu = '\0'; 131*42396Sbostic 13240556Skarels if (!found) { 13340556Skarels /* 13440556Skarels * We didn't find the current level in its parent 13540556Skarels * directory; figure out what to complain about. 13640556Skarels */ 137*42396Sbostic if (save_errno) { 13840556Skarels errno = save_errno; 13940556Skarels goto err; 14040556Skarels } 14140556Skarels (void) sprintf(store, "%s not found in %s?\n", 14240556Skarels first ? "." : pp, up); 14340556Skarels return ((char *)NULL); 14440556Skarels } 1459986Ssam } 14640556Skarels err: 14740556Skarels (void) sprintf(store, "getwd: %s: %s", file, strerror(errno)); 14840556Skarels return ((char *)NULL); 1499986Ssam } 150