xref: /csrg-svn/lib/libc/gen/getcwd.c (revision 10155)
1*10155Ssam /*	@(#)getcwd.c	4.6	(Berkeley)	01/05/83	*/
29986Ssam 
39986Ssam /*
4*10155Ssam  * getwd() returns the pathname of the current working directory. On error
5*10155Ssam  * 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 
11*10155Ssam #define CURDIR		"."
12*10155Ssam #define GETWDERR(s)	strcpy(pathname, (s));
13*10155Ssam #define PARENTDIR	".."
14*10155Ssam #define PATHSEP		"/"
15*10155Ssam #define PATHSIZE	1024
16*10155Ssam #define ROOTDIR		"/"
179986Ssam 
18*10155Ssam static int pathsize;			/* pathname length */
1910127Ssam 
209986Ssam char *
21*10155Ssam getwd(pathname)
22*10155Ssam 	char *pathname;
239986Ssam {
24*10155Ssam 	char pathbuf[PATHSIZE];		/* temporary pathname buffer */
25*10155Ssam 	char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */
26*10155Ssam 	char *prepend();		/* prepend dirname to pathname */
27*10155Ssam 	dev_t rdev;			/* root device number */
28*10155Ssam 	DIR *dirp;			/* directory stream */
29*10155Ssam 	ino_t rino;			/* root inode number */
30*10155Ssam 	struct direct *dir;		/* directory entry struct */
31*10155Ssam 	struct stat d ,dd;		/* file status struct */
329986Ssam 
33*10155Ssam 	pathsize = 0;
34*10155Ssam 	*pnptr = '\0';
35*10155Ssam 	stat(ROOTDIR, &d);
369986Ssam 	rdev = d.st_dev;
379986Ssam 	rino = d.st_ino;
389986Ssam 	for (;;) {
39*10155Ssam 		stat(CURDIR, &d);
40*10155Ssam 		if (d.st_ino == rino && d.st_dev == rdev)
41*10155Ssam 			break;		/* reached root directory */
42*10155Ssam 		if ((dirp = opendir(PARENTDIR)) == NULL) {
43*10155Ssam 			GETWDERR("getwd: can't open ..");
44*10155Ssam 			goto fail;
45*10155Ssam 		}
46*10155Ssam 		if (chdir(PARENTDIR) < 0) {
47*10155Ssam 			GETWDERR("getwd: can't chdir to ..");
48*10155Ssam 			goto fail;
49*10155Ssam 		}
50*10155Ssam 		fstat(dirp->dd_fd, &dd);
5110126Ssam 		if (d.st_dev == dd.st_dev) {
52*10155Ssam 			if (d.st_ino == dd.st_ino) {
53*10155Ssam 				/* reached root directory */
54*10155Ssam 				closedir(dirp);
55*10155Ssam 				break;
56*10155Ssam 			}
5710140Ssam 			do {
58*10155Ssam 				if ((dir = readdir(dirp)) == NULL) {
59*10155Ssam 					closedir(dirp);
60*10155Ssam 					GETWDERR("getwd: read error in ..");
61*10155Ssam 					goto fail;
62*10155Ssam 				}
6310140Ssam 			} while (dir->d_ino != d.st_ino);
6410126Ssam 		} else
6510126Ssam 			do {
66*10155Ssam 				if((dir = readdir(dirp)) == NULL) {
67*10155Ssam 					closedir(dirp);
68*10155Ssam 					GETWDERR("getwd: read error in ..");
69*10155Ssam 					goto fail;
70*10155Ssam 				}
719986Ssam 				stat(dir->d_name, &dd);
729986Ssam 			} while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev);
73*10155Ssam 		closedir(dirp);
74*10155Ssam 		pnptr = prepend(PATHSEP, prepend(dir->d_name, pnptr));
759986Ssam 	}
76*10155Ssam 	if (*pnptr == '\0')		/* current dir == root dir */
77*10155Ssam 		strcpy(pathname, ROOTDIR);
78*10155Ssam 	else {
79*10155Ssam 		strcpy(pathname, pnptr);
80*10155Ssam 		if (chdir(pnptr) < 0) {
81*10155Ssam 			GETWDERR("getwd: can't change back to .");
82*10155Ssam 			return (NULL);
83*10155Ssam 		}
84*10155Ssam 	}
85*10155Ssam 	return (pathname);
86*10155Ssam 
87*10155Ssam fail:
88*10155Ssam 	chdir(prepend(CURDIR, pnptr));
89*10155Ssam 	return (NULL);
909986Ssam }
919986Ssam 
92*10155Ssam /*
93*10155Ssam  * prepend() tacks a directory name onto the front of a pathname.
94*10155Ssam  */
95*10155Ssam static char *
96*10155Ssam prepend(dirname, pathname)
97*10155Ssam 	register char *dirname;
98*10155Ssam 	register char *pathname;
999986Ssam {
100*10155Ssam 	register int i;			/* directory name size counter */
1019986Ssam 
102*10155Ssam 	for (i = 0; *dirname != '\0'; i++, dirname++)
103*10155Ssam 		continue;
104*10155Ssam 	if ((pathsize += i) < PATHSIZE)
105*10155Ssam 		while (i-- > 0)
106*10155Ssam 			*--pathname = *--dirname;
107*10155Ssam 	return (pathname);
1089986Ssam }
109