xref: /csrg-svn/lib/libc/gen/getcwd.c (revision 42396)
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