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