xref: /csrg-svn/lib/libc/gen/getcwd.c (revision 10156)
1 /*	@(#)getcwd.c	4.7	(Berkeley)	01/05/83	*/
2 
3 /*
4  * getwd() returns the pathname of the current working directory. On error
5  * an error message is copied to pathname and null pointer is returned.
6  */
7 #include <sys/param.h>
8 #include <sys/stat.h>
9 #include <sys/dir.h>
10 
11 #define CURDIR		"."
12 #define GETWDERR(s)	strcpy(pathname, (s));
13 #define PARENTDIR	".."
14 #define PATHSEP		"/"
15 #define ROOTDIR		"/"
16 
17 static int pathsize;			/* pathname length */
18 
19 char *
20 getwd(pathname)
21 	char *pathname;
22 {
23 	char pathbuf[MAXPATHLEN];		/* temporary pathname buffer */
24 	char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */
25 	char *prepend();		/* prepend dirname to pathname */
26 	dev_t rdev;			/* root device number */
27 	DIR *dirp;			/* directory stream */
28 	ino_t rino;			/* root inode number */
29 	struct direct *dir;		/* directory entry struct */
30 	struct stat d ,dd;		/* file status struct */
31 
32 	pathsize = 0;
33 	*pnptr = '\0';
34 	stat(ROOTDIR, &d);
35 	rdev = d.st_dev;
36 	rino = d.st_ino;
37 	for (;;) {
38 		stat(CURDIR, &d);
39 		if (d.st_ino == rino && d.st_dev == rdev)
40 			break;		/* reached root directory */
41 		if ((dirp = opendir(PARENTDIR)) == NULL) {
42 			GETWDERR("getwd: can't open ..");
43 			goto fail;
44 		}
45 		if (chdir(PARENTDIR) < 0) {
46 			GETWDERR("getwd: can't chdir to ..");
47 			goto fail;
48 		}
49 		fstat(dirp->dd_fd, &dd);
50 		if (d.st_dev == dd.st_dev) {
51 			if (d.st_ino == dd.st_ino) {
52 				/* reached root directory */
53 				closedir(dirp);
54 				break;
55 			}
56 			do {
57 				if ((dir = readdir(dirp)) == NULL) {
58 					closedir(dirp);
59 					GETWDERR("getwd: read error in ..");
60 					goto fail;
61 				}
62 			} while (dir->d_ino != d.st_ino);
63 		} else
64 			do {
65 				if((dir = readdir(dirp)) == NULL) {
66 					closedir(dirp);
67 					GETWDERR("getwd: read error in ..");
68 					goto fail;
69 				}
70 				stat(dir->d_name, &dd);
71 			} while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev);
72 		closedir(dirp);
73 		pnptr = prepend(PATHSEP, prepend(dir->d_name, pnptr));
74 	}
75 	if (*pnptr == '\0')		/* current dir == root dir */
76 		strcpy(pathname, ROOTDIR);
77 	else {
78 		strcpy(pathname, pnptr);
79 		if (chdir(pnptr) < 0) {
80 			GETWDERR("getwd: can't change back to .");
81 			return (NULL);
82 		}
83 	}
84 	return (pathname);
85 
86 fail:
87 	chdir(prepend(CURDIR, pnptr));
88 	return (NULL);
89 }
90 
91 /*
92  * prepend() tacks a directory name onto the front of a pathname.
93  */
94 static char *
95 prepend(dirname, pathname)
96 	register char *dirname;
97 	register char *pathname;
98 {
99 	register int i;			/* directory name size counter */
100 
101 	for (i = 0; *dirname != '\0'; i++, dirname++)
102 		continue;
103 	if ((pathsize += i) < MAXPATHLEN)
104 		while (i-- > 0)
105 			*--pathname = *--dirname;
106 	return (pathname);
107 }
108