xref: /csrg-svn/lib/libc/gen/getcwd.c (revision 42625)
121345Sdist /*
237209Sbostic  * Copyright (c) 1989 The Regents of the University of California.
337209Sbostic  * All rights reserved.
437209Sbostic  *
5*42625Sbostic  * %sccs.include.redist.c%
621345Sdist  */
79986Ssam 
826565Sdonn #if defined(LIBC_SCCS) && !defined(lint)
9*42625Sbostic static char sccsid[] = "@(#)getcwd.c	5.8 (Berkeley) 06/01/90";
1037209Sbostic #endif /* LIBC_SCCS and not lint */
1121345Sdist 
1210088Ssam #include <sys/param.h>
1310088Ssam #include <sys/stat.h>
1437209Sbostic #include <dirent.h>
1542396Sbostic #include <string.h>
169986Ssam 
1742396Sbostic #define	ISDOT(dp) \
1842396Sbostic 	(dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
1942396Sbostic 	    dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
2042396Sbostic 
219986Ssam char *
2237209Sbostic getwd(store)
2337209Sbostic 	char *store;
249986Ssam {
2537209Sbostic 	extern int errno;
2642396Sbostic 	register struct dirent *dp;
2737209Sbostic 	register DIR *dir;
2842396Sbostic 	register ino_t ino;
2942396Sbostic 	register char *pp, *pu;
3037209Sbostic 	register int first;
3142396Sbostic 	struct stat s;
3242396Sbostic 	dev_t root_dev, dev;
3337209Sbostic 	ino_t root_ino;
3440556Skarels 	int save_errno, found;
3542396Sbostic 	char path[MAXPATHLEN], up[MAXPATHLEN], *file;
369986Ssam 
3742396Sbostic 	/* save root values */
3840556Skarels 	if (stat("/", &s)) {
3940556Skarels 		file = "/";
4037209Sbostic 		goto err;
4140556Skarels 	}
4237209Sbostic 	root_dev = s.st_dev;
4337209Sbostic 	root_ino = s.st_ino;
4442396Sbostic 
4542396Sbostic 	/* init path pointer; built from the end of the buffer */
4637209Sbostic 	pp = path + sizeof(path) - 1;
4737209Sbostic 	*pp = '\0';
4842396Sbostic 
4942396Sbostic 	/* special case first stat, it's ".", not ".." */
5042396Sbostic 	up[0] = '.';
5142396Sbostic 	up[1] = '\0';
5242396Sbostic 
5337209Sbostic 	for (pu = up, first = 1;; first = 0) {
5442396Sbostic 		/* stat current level */
5542396Sbostic 		if (lstat(up, &s)) {
5642396Sbostic 			file = up;
5742396Sbostic 			goto err;
5842396Sbostic 		}
5942396Sbostic 
6042396Sbostic 		/* save current node values */
6142396Sbostic 		ino = s.st_ino;
6242396Sbostic 		dev = s.st_dev;
6342396Sbostic 
6442396Sbostic 		/* check for root */
6542396Sbostic 		if (root_dev == dev && root_ino == ino) {
6637209Sbostic 			*store = '/';
6740556Skarels 			(void) strcpy(store + 1, pp);
6840556Skarels 			return (store);
6910155Ssam 		}
7042396Sbostic 
7137209Sbostic 		*pu++ = '.';
7237209Sbostic 		*pu++ = '.';
7337209Sbostic 		*pu = '\0';
7442396Sbostic 
7542396Sbostic 		/* open and stat parent */
7642396Sbostic 		if (!(dir = opendir(up)) || fstat(dirfd(dir), &s)) {
7740556Skarels 			file = up;
7840556Skarels 			goto err;
7937209Sbostic 		}
8042396Sbostic 		found = save_errno = 0;
8142396Sbostic 
8237209Sbostic 		*pu++ = '/';
8342396Sbostic 
8442396Sbostic 		/*
8542396Sbostic 		 * if it's a mount point you have to stat each element because
8642396Sbostic 		 * the inode number in the directory is for the entry in the
8742396Sbostic 		 * parent directory, not the inode number of the mounted file.
8842396Sbostic 		 */
8942396Sbostic 		if (s.st_dev == dev) {
9042396Sbostic 			while (dp = readdir(dir))
9142396Sbostic 				if (dp->d_fileno == ino)
9242396Sbostic 					goto hit;
9342396Sbostic 		} else {
9442396Sbostic 			while (dp = readdir(dir)) {
9542396Sbostic 				if (ISDOT(dp))
9642396Sbostic 					continue;
9742396Sbostic 				bcopy(dp->d_name, pu, dp->d_namlen + 1);
9842396Sbostic 				if (lstat(up, &s)) {
9942396Sbostic 					file = dp->d_name;
10042396Sbostic 					save_errno = errno;
10142396Sbostic 					errno = 0;
10242396Sbostic 					continue;
10342396Sbostic 				}
10442396Sbostic 				if (s.st_dev == dev && s.st_ino == ino) {
10542396Sbostic hit:					if (!first)
10642396Sbostic 						*--pp = '/';
10742396Sbostic 					pp -= dp->d_namlen;
10842396Sbostic 					bcopy(dp->d_name, pp, dp->d_namlen);
10942396Sbostic 					found = 1;
11042396Sbostic 					break;
11142396Sbostic 				}
11242396Sbostic 			}
11342396Sbostic 			if (errno) {
11442396Sbostic 				file = up;
11540556Skarels 				save_errno = errno;
11640556Skarels 			}
11737209Sbostic 		}
11842396Sbostic 		(void) closedir(dir);
11942396Sbostic 
12037209Sbostic 		*pu = '\0';
12142396Sbostic 
12240556Skarels 		if (!found) {
12340556Skarels 			/*
12440556Skarels 			 * We didn't find the current level in its parent
12540556Skarels 			 * directory; figure out what to complain about.
12640556Skarels 			 */
12742396Sbostic 			if (save_errno) {
12840556Skarels 				errno = save_errno;
12940556Skarels 				goto err;
13040556Skarels 			}
13140556Skarels 			(void) sprintf(store, "%s not found in %s?\n",
13240556Skarels 				first ? "." : pp, up);
13340556Skarels 			return ((char *)NULL);
13440556Skarels 		}
1359986Ssam 	}
13640556Skarels err:
13740556Skarels 	(void) sprintf(store, "getwd: %s: %s", file, strerror(errno));
13840556Skarels 	return ((char *)NULL);
1399986Ssam }
140