xref: /original-bsd/lib/libc/gen/getcwd.c (revision 8431ec24)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #if defined(LIBC_SCCS) && !defined(lint)
19 static char sccsid[] = "@(#)getcwd.c	5.6 (Berkeley) 03/20/90";
20 #endif /* LIBC_SCCS and not lint */
21 
22 #include <sys/param.h>
23 #include <sys/stat.h>
24 #include <dirent.h>
25 
26 char *
27 getwd(store)
28 	char *store;
29 {
30 	extern int errno;
31 	register DIR *dir;
32 	register struct dirent *dp;
33 	register int first;
34 	register char *pp, *pu;
35 	struct stat s, tmp;
36 	dev_t root_dev;
37 	ino_t root_ino;
38 	int save_errno, found;
39 	char path[MAXPATHLEN], up[MAXPATHLEN], *file, *strerror();
40 
41 	if (stat("/", &s)) {
42 		file = "/";
43 		goto err;
44 	}
45 	root_dev = s.st_dev;
46 	root_ino = s.st_ino;
47 	if (stat(".", &s)) {
48 		file = ".";
49 		goto err;
50 	}
51 	pp = path + sizeof(path) - 1;
52 	*pp = '\0';
53 	for (pu = up, first = 1;; first = 0) {
54 		if (root_dev == s.st_dev && root_ino == s.st_ino) {
55 			*store = '/';
56 			(void) strcpy(store + 1, pp);
57 			return (store);
58 		}
59 		*pu++ = '.';
60 		*pu++ = '.';
61 		*pu = '\0';
62 		if (!(dir = opendir(up))) {
63 			file = up;
64 			goto err;
65 		}
66 		*pu++ = '/';
67 		found = 0;
68 		file = NULL;
69 		while (errno = 0, dp = readdir(dir)) {
70 			if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
71 			    dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
72 				continue;
73 			bcopy(dp->d_name, pu, dp->d_namlen + 1);
74 			if (lstat(up, &tmp)) {
75 				file = dp->d_name;
76 				save_errno = errno;
77 				continue;
78 			}
79 			if (tmp.st_dev == s.st_dev && tmp.st_ino == s.st_ino) {
80 				if (!first)
81 					*--pp = '/';
82 				pp -= dp->d_namlen;
83 				bcopy(dp->d_name, pp, dp->d_namlen);
84 				found = 1;
85 				break;
86 			}
87 		}
88 		if (errno) {
89 			save_errno = errno;
90 			file = up;
91 		}
92 		closedir(dir);
93 		*pu = '\0';
94 		if (!found) {
95 			/*
96 			 * We didn't find the current level in its parent
97 			 * directory; figure out what to complain about.
98 			 */
99 			if (file) {
100 				errno = save_errno;
101 				goto err;
102 			}
103 			(void) sprintf(store, "%s not found in %s?\n",
104 				first ? "." : pp, up);
105 			return ((char *)NULL);
106 		}
107 
108 		/* stat "." at current level, then ascend */
109 		if (lstat(up, &s)) {
110 			file = up;
111 			goto err;
112 		}
113 	}
114 
115 err:
116 	(void) sprintf(store, "getwd: %s: %s", file, strerror(errno));
117 	return ((char *)NULL);
118 }
119