1*433d6423SLionel Sambuc /* getcwd() - get the name of the current working directory.
2*433d6423SLionel Sambuc * Author: Kees J. Bot
3*433d6423SLionel Sambuc * 30 Apr 1989
4*433d6423SLionel Sambuc */
5*433d6423SLionel Sambuc
6*433d6423SLionel Sambuc #include <sys/cdefs.h>
7*433d6423SLionel Sambuc #include "namespace.h"
8*433d6423SLionel Sambuc
9*433d6423SLionel Sambuc #include <sys/types.h>
10*433d6423SLionel Sambuc #include <sys/stat.h>
11*433d6423SLionel Sambuc #include <errno.h>
12*433d6423SLionel Sambuc #include <unistd.h>
13*433d6423SLionel Sambuc #include <dirent.h>
14*433d6423SLionel Sambuc #include <limits.h>
15*433d6423SLionel Sambuc #include <string.h>
16*433d6423SLionel Sambuc
17*433d6423SLionel Sambuc /* libc-private interface */
18*433d6423SLionel Sambuc int __getcwd(char *, size_t);
19*433d6423SLionel Sambuc
addpath(const char * path,char ** ap,const char * entry)20*433d6423SLionel Sambuc static int addpath(const char *path, char **ap, const char *entry)
21*433d6423SLionel Sambuc /* Add the name of a directory entry at the front of the path being built.
22*433d6423SLionel Sambuc * Note that the result always starts with a slash.
23*433d6423SLionel Sambuc */
24*433d6423SLionel Sambuc {
25*433d6423SLionel Sambuc const char *e= entry;
26*433d6423SLionel Sambuc char *p= *ap;
27*433d6423SLionel Sambuc
28*433d6423SLionel Sambuc while (*e != 0) e++;
29*433d6423SLionel Sambuc
30*433d6423SLionel Sambuc while (e > entry && p > path) *--p = *--e;
31*433d6423SLionel Sambuc
32*433d6423SLionel Sambuc if (p == path) return -1;
33*433d6423SLionel Sambuc *--p = '/';
34*433d6423SLionel Sambuc *ap= p;
35*433d6423SLionel Sambuc return 0;
36*433d6423SLionel Sambuc }
37*433d6423SLionel Sambuc
recover(char * p)38*433d6423SLionel Sambuc static int recover(char *p)
39*433d6423SLionel Sambuc /* Undo all those chdir("..")'s that have been recorded by addpath. This
40*433d6423SLionel Sambuc * has to be done entry by entry, because the whole pathname may be too long.
41*433d6423SLionel Sambuc */
42*433d6423SLionel Sambuc {
43*433d6423SLionel Sambuc int e= errno, slash;
44*433d6423SLionel Sambuc char *p0;
45*433d6423SLionel Sambuc
46*433d6423SLionel Sambuc while (*p != 0) {
47*433d6423SLionel Sambuc p0= ++p;
48*433d6423SLionel Sambuc
49*433d6423SLionel Sambuc do p++; while (*p != 0 && *p != '/');
50*433d6423SLionel Sambuc slash= *p; *p= 0;
51*433d6423SLionel Sambuc
52*433d6423SLionel Sambuc if (chdir(p0) < 0) return -1;
53*433d6423SLionel Sambuc *p= slash;
54*433d6423SLionel Sambuc }
55*433d6423SLionel Sambuc errno= e;
56*433d6423SLionel Sambuc return 0;
57*433d6423SLionel Sambuc }
58*433d6423SLionel Sambuc
__getcwd(char * path,size_t size)59*433d6423SLionel Sambuc int __getcwd(char *path, size_t size)
60*433d6423SLionel Sambuc {
61*433d6423SLionel Sambuc struct stat above, current, tmp;
62*433d6423SLionel Sambuc struct dirent *entry;
63*433d6423SLionel Sambuc DIR *d;
64*433d6423SLionel Sambuc char *p, *up;
65*433d6423SLionel Sambuc const char *dotdot = "..";
66*433d6423SLionel Sambuc int cycle;
67*433d6423SLionel Sambuc
68*433d6423SLionel Sambuc if (path == NULL || size <= 1) { errno= EINVAL; return -1; }
69*433d6423SLionel Sambuc
70*433d6423SLionel Sambuc p= path + size;
71*433d6423SLionel Sambuc *--p = 0;
72*433d6423SLionel Sambuc
73*433d6423SLionel Sambuc if (stat(".", ¤t) < 0) return -1;
74*433d6423SLionel Sambuc
75*433d6423SLionel Sambuc while (1) {
76*433d6423SLionel Sambuc if (stat(dotdot, &above) < 0) { recover(p); return -1; }
77*433d6423SLionel Sambuc
78*433d6423SLionel Sambuc if (above.st_dev == current.st_dev
79*433d6423SLionel Sambuc && above.st_ino == current.st_ino)
80*433d6423SLionel Sambuc break; /* Root dir found */
81*433d6423SLionel Sambuc
82*433d6423SLionel Sambuc if ((d= opendir(dotdot)) == NULL) { recover(p); return -1; }
83*433d6423SLionel Sambuc
84*433d6423SLionel Sambuc /* Cycle is 0 for a simple inode nr search, or 1 for a search
85*433d6423SLionel Sambuc * for inode *and* device nr.
86*433d6423SLionel Sambuc */
87*433d6423SLionel Sambuc cycle= above.st_dev == current.st_dev ? 0 : 1;
88*433d6423SLionel Sambuc
89*433d6423SLionel Sambuc do {
90*433d6423SLionel Sambuc char name[3 + NAME_MAX + 1];
91*433d6423SLionel Sambuc
92*433d6423SLionel Sambuc tmp.st_ino= 0;
93*433d6423SLionel Sambuc if ((entry= readdir(d)) == NULL) {
94*433d6423SLionel Sambuc switch (++cycle) {
95*433d6423SLionel Sambuc case 1:
96*433d6423SLionel Sambuc rewinddir(d);
97*433d6423SLionel Sambuc continue;
98*433d6423SLionel Sambuc case 2:
99*433d6423SLionel Sambuc closedir(d);
100*433d6423SLionel Sambuc errno= ENOENT;
101*433d6423SLionel Sambuc recover(p);
102*433d6423SLionel Sambuc return -1;
103*433d6423SLionel Sambuc }
104*433d6423SLionel Sambuc }
105*433d6423SLionel Sambuc if (strcmp(entry->d_name, ".") == 0) continue;
106*433d6423SLionel Sambuc if (strcmp(entry->d_name, "..") == 0) continue;
107*433d6423SLionel Sambuc
108*433d6423SLionel Sambuc switch (cycle) {
109*433d6423SLionel Sambuc case 0:
110*433d6423SLionel Sambuc /* Simple test on inode nr. */
111*433d6423SLionel Sambuc if (entry->d_ino != current.st_ino) continue;
112*433d6423SLionel Sambuc /*FALL THROUGH*/
113*433d6423SLionel Sambuc
114*433d6423SLionel Sambuc case 1:
115*433d6423SLionel Sambuc /* Current is mounted. */
116*433d6423SLionel Sambuc strcpy(name, "../");
117*433d6423SLionel Sambuc strcpy(name+3, entry->d_name);
118*433d6423SLionel Sambuc if (stat(name, &tmp) < 0) continue;
119*433d6423SLionel Sambuc break;
120*433d6423SLionel Sambuc }
121*433d6423SLionel Sambuc } while (tmp.st_ino != current.st_ino
122*433d6423SLionel Sambuc || tmp.st_dev != current.st_dev);
123*433d6423SLionel Sambuc
124*433d6423SLionel Sambuc up= p;
125*433d6423SLionel Sambuc if (addpath(path, &up, entry->d_name) < 0) {
126*433d6423SLionel Sambuc closedir(d);
127*433d6423SLionel Sambuc errno = ERANGE;
128*433d6423SLionel Sambuc recover(p);
129*433d6423SLionel Sambuc return -1;
130*433d6423SLionel Sambuc }
131*433d6423SLionel Sambuc closedir(d);
132*433d6423SLionel Sambuc
133*433d6423SLionel Sambuc if (chdir(dotdot) < 0) { recover(p); return -1; }
134*433d6423SLionel Sambuc p= up;
135*433d6423SLionel Sambuc
136*433d6423SLionel Sambuc current= above;
137*433d6423SLionel Sambuc }
138*433d6423SLionel Sambuc if (recover(p) < 0) return -1; /* Undo all those chdir("..")'s. */
139*433d6423SLionel Sambuc if (*p == 0) *--p = '/'; /* Cwd is "/" if nothing added */
140*433d6423SLionel Sambuc if (p > path) strcpy(path, p); /* Move string to start of path. */
141*433d6423SLionel Sambuc return 0;
142*433d6423SLionel Sambuc }
143