xref: /csrg-svn/lib/libc/gen/getcwd.c (revision 10156)
1*10156Ssam /*	@(#)getcwd.c	4.7	(Berkeley)	01/05/83	*/
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 CURDIR		"."
1210155Ssam #define GETWDERR(s)	strcpy(pathname, (s));
1310155Ssam #define PARENTDIR	".."
1410155Ssam #define PATHSEP		"/"
1510155Ssam #define ROOTDIR		"/"
169986Ssam 
1710155Ssam static int pathsize;			/* pathname length */
1810127Ssam 
199986Ssam char *
2010155Ssam getwd(pathname)
2110155Ssam 	char *pathname;
229986Ssam {
23*10156Ssam 	char pathbuf[MAXPATHLEN];		/* temporary pathname buffer */
2410155Ssam 	char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */
2510155Ssam 	char *prepend();		/* prepend dirname to pathname */
2610155Ssam 	dev_t rdev;			/* root device number */
2710155Ssam 	DIR *dirp;			/* directory stream */
2810155Ssam 	ino_t rino;			/* root inode number */
2910155Ssam 	struct direct *dir;		/* directory entry struct */
3010155Ssam 	struct stat d ,dd;		/* file status struct */
319986Ssam 
3210155Ssam 	pathsize = 0;
3310155Ssam 	*pnptr = '\0';
3410155Ssam 	stat(ROOTDIR, &d);
359986Ssam 	rdev = d.st_dev;
369986Ssam 	rino = d.st_ino;
379986Ssam 	for (;;) {
3810155Ssam 		stat(CURDIR, &d);
3910155Ssam 		if (d.st_ino == rino && d.st_dev == rdev)
4010155Ssam 			break;		/* reached root directory */
4110155Ssam 		if ((dirp = opendir(PARENTDIR)) == NULL) {
4210155Ssam 			GETWDERR("getwd: can't open ..");
4310155Ssam 			goto fail;
4410155Ssam 		}
4510155Ssam 		if (chdir(PARENTDIR) < 0) {
4610155Ssam 			GETWDERR("getwd: can't chdir to ..");
4710155Ssam 			goto fail;
4810155Ssam 		}
4910155Ssam 		fstat(dirp->dd_fd, &dd);
5010126Ssam 		if (d.st_dev == dd.st_dev) {
5110155Ssam 			if (d.st_ino == dd.st_ino) {
5210155Ssam 				/* reached root directory */
5310155Ssam 				closedir(dirp);
5410155Ssam 				break;
5510155Ssam 			}
5610140Ssam 			do {
5710155Ssam 				if ((dir = readdir(dirp)) == NULL) {
5810155Ssam 					closedir(dirp);
5910155Ssam 					GETWDERR("getwd: read error in ..");
6010155Ssam 					goto fail;
6110155Ssam 				}
6210140Ssam 			} while (dir->d_ino != d.st_ino);
6310126Ssam 		} else
6410126Ssam 			do {
6510155Ssam 				if((dir = readdir(dirp)) == NULL) {
6610155Ssam 					closedir(dirp);
6710155Ssam 					GETWDERR("getwd: read error in ..");
6810155Ssam 					goto fail;
6910155Ssam 				}
709986Ssam 				stat(dir->d_name, &dd);
719986Ssam 			} while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev);
7210155Ssam 		closedir(dirp);
7310155Ssam 		pnptr = prepend(PATHSEP, prepend(dir->d_name, pnptr));
749986Ssam 	}
7510155Ssam 	if (*pnptr == '\0')		/* current dir == root dir */
7610155Ssam 		strcpy(pathname, ROOTDIR);
7710155Ssam 	else {
7810155Ssam 		strcpy(pathname, pnptr);
7910155Ssam 		if (chdir(pnptr) < 0) {
8010155Ssam 			GETWDERR("getwd: can't change back to .");
8110155Ssam 			return (NULL);
8210155Ssam 		}
8310155Ssam 	}
8410155Ssam 	return (pathname);
8510155Ssam 
8610155Ssam fail:
8710155Ssam 	chdir(prepend(CURDIR, pnptr));
8810155Ssam 	return (NULL);
899986Ssam }
909986Ssam 
9110155Ssam /*
9210155Ssam  * prepend() tacks a directory name onto the front of a pathname.
9310155Ssam  */
9410155Ssam static char *
9510155Ssam prepend(dirname, pathname)
9610155Ssam 	register char *dirname;
9710155Ssam 	register char *pathname;
989986Ssam {
9910155Ssam 	register int i;			/* directory name size counter */
1009986Ssam 
10110155Ssam 	for (i = 0; *dirname != '\0'; i++, dirname++)
10210155Ssam 		continue;
103*10156Ssam 	if ((pathsize += i) < MAXPATHLEN)
10410155Ssam 		while (i-- > 0)
10510155Ssam 			*--pathname = *--dirname;
10610155Ssam 	return (pathname);
1079986Ssam }
108