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