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