xref: /csrg-svn/lib/libc/gen/getcwd.c (revision 17867)
1*17867Sralph /*	@(#)getcwd.c	4.10	(Berkeley)	01/24/85	*/
29986Ssam 
39986Ssam /*
410155Ssam  * getwd() returns the pathname of the current working directory. On error
510155Ssam  * an error message is copied to pathname and null pointer is returned.
69986Ssam  */
710088Ssam #include <sys/param.h>
810088Ssam #include <sys/stat.h>
910088Ssam #include <sys/dir.h>
109986Ssam 
1110155Ssam #define GETWDERR(s)	strcpy(pathname, (s));
129986Ssam 
1311370Snicklin char *strcpy();
1410155Ssam static int pathsize;			/* pathname length */
1510127Ssam 
169986Ssam char *
1710155Ssam getwd(pathname)
1810155Ssam 	char *pathname;
199986Ssam {
2010156Ssam 	char pathbuf[MAXPATHLEN];		/* temporary pathname buffer */
2110155Ssam 	char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */
22*17867Sralph 	char curdir[MAXPATHLEN];	/* current directory buffer */
23*17867Sralph 	char *dptr = curdir;		/* directory pointer */
2410155Ssam 	char *prepend();		/* prepend dirname to pathname */
25*17867Sralph 	dev_t cdev, rdev;		/* current & root device number */
26*17867Sralph 	ino_t cino, rino;		/* current & root inode number */
2710155Ssam 	DIR *dirp;			/* directory stream */
2810155Ssam 	struct direct *dir;		/* directory entry struct */
29*17867Sralph 	struct stat d, dd;		/* file status struct */
309986Ssam 
3110155Ssam 	pathsize = 0;
3210155Ssam 	*pnptr = '\0';
33*17867Sralph 	if (stat("/", &d) < 0) {
34*17867Sralph 		GETWDERR("getwd: can't stat /");
35*17867Sralph 		return (NULL);
36*17867Sralph 	}
379986Ssam 	rdev = d.st_dev;
389986Ssam 	rino = d.st_ino;
39*17867Sralph 	strcpy(dptr, "./");
40*17867Sralph 	dptr += 2;
41*17867Sralph 	if (stat(curdir, &d) < 0) {
42*17867Sralph 		GETWDERR("getwd: can't stat .");
43*17867Sralph 		return (NULL);
44*17867Sralph 	}
459986Ssam 	for (;;) {
4610155Ssam 		if (d.st_ino == rino && d.st_dev == rdev)
4710155Ssam 			break;		/* reached root directory */
48*17867Sralph 		cino = d.st_ino;
49*17867Sralph 		cdev = d.st_dev;
50*17867Sralph 		strcpy(dptr, "../");
51*17867Sralph 		dptr += 3;
52*17867Sralph 		if ((dirp = opendir(curdir)) == NULL) {
5310155Ssam 			GETWDERR("getwd: can't open ..");
54*17867Sralph 			return (NULL);
5510155Ssam 		}
56*17867Sralph 		fstat(dirp->dd_fd, &d);
57*17867Sralph 		if (cdev == d.st_dev) {
58*17867Sralph 			if (cino == d.st_ino) {
5910155Ssam 				/* reached root directory */
6010155Ssam 				closedir(dirp);
6110155Ssam 				break;
6210155Ssam 			}
6310140Ssam 			do {
6410155Ssam 				if ((dir = readdir(dirp)) == NULL) {
6510155Ssam 					closedir(dirp);
6610155Ssam 					GETWDERR("getwd: read error in ..");
67*17867Sralph 					return (NULL);
6810155Ssam 				}
69*17867Sralph 			} while (dir->d_ino != cino);
7010126Ssam 		} else
7110126Ssam 			do {
72*17867Sralph 				if ((dir = readdir(dirp)) == NULL) {
7310155Ssam 					closedir(dirp);
7410155Ssam 					GETWDERR("getwd: read error in ..");
75*17867Sralph 					return (NULL);
7610155Ssam 				}
77*17867Sralph 				strcpy(dptr, dir->d_name);
78*17867Sralph 				lstat(curdir, &dd);
79*17867Sralph 			} while(dd.st_ino != cino || dd.st_dev != cdev);
8010155Ssam 		closedir(dirp);
81*17867Sralph 		pnptr = prepend("/", prepend(dir->d_name, pnptr));
829986Ssam 	}
8310155Ssam 	if (*pnptr == '\0')		/* current dir == root dir */
84*17867Sralph 		strcpy(pathname, "/");
85*17867Sralph 	else
8610155Ssam 		strcpy(pathname, pnptr);
8710155Ssam 	return (pathname);
889986Ssam }
899986Ssam 
9010155Ssam /*
9110155Ssam  * prepend() tacks a directory name onto the front of a pathname.
9210155Ssam  */
9310155Ssam static char *
9410155Ssam prepend(dirname, pathname)
9510155Ssam 	register char *dirname;
9610155Ssam 	register char *pathname;
979986Ssam {
9810155Ssam 	register int i;			/* directory name size counter */
999986Ssam 
10010155Ssam 	for (i = 0; *dirname != '\0'; i++, dirname++)
10110155Ssam 		continue;
10210156Ssam 	if ((pathsize += i) < MAXPATHLEN)
10310155Ssam 		while (i-- > 0)
10410155Ssam 			*--pathname = *--dirname;
10510155Ssam 	return (pathname);
1069986Ssam }
107