dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libast / common / misc / getcwd.c
blob2f60b17129bacefe01c08594b31bacca0b04945c
1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
20 * *
21 ***********************************************************************/
22 #pragma prototyped
24 * Glenn Fowler
25 * AT&T Research
27 * pwd library support
30 #include <ast.h>
32 #if _WINIX
34 NoN(getcwd)
36 #else
38 #include <ast_dir.h>
39 #include <error.h>
40 #include <fs3d.h>
42 #ifndef ERANGE
43 #define ERANGE E2BIG
44 #endif
46 #define ERROR(e) { errno = e; goto error; }
48 struct dirlist /* long path chdir(2) component */
50 struct dirlist* next; /* next component */
51 int index; /* index from end of buf */
55 * pop long dir component chdir stack
58 static int
59 popdir(register struct dirlist* d, register char* end)
61 register struct dirlist* dp;
62 int v;
64 v = 0;
65 while (dp = d)
67 d = d->next;
68 if (!v)
70 if (d) *(end - d->index - 1) = 0;
71 v = chdir(end - dp->index);
72 if (d) *(end - d->index - 1) = '/';
74 free(dp);
76 return v;
80 * push long dir component onto stack
83 static struct dirlist*
84 pushdir(register struct dirlist* d, char* dots, char* path, char* end)
86 register struct dirlist* p;
88 if (!(p = newof(0, struct dirlist, 1, 0)) || chdir(dots))
90 if (p) free(p);
91 if (d) popdir(d, end);
92 return 0;
94 p->index = end - path;
95 p->next = d;
96 return p;
100 * return a pointer to the absolute path name of .
101 * this path name may be longer than PATH_MAX
103 * a few environment variables are checked before the search algorithm
104 * return value is placed in buf of len chars
105 * if buf is 0 then space is allocated via malloc() with
106 * len extra chars after the path name
107 * 0 is returned on error with errno set as appropriate
110 char*
111 getcwd(char* buf, size_t len)
113 register char* d;
114 register char* p;
115 register char* s;
116 DIR* dirp = 0;
117 int n;
118 int x;
119 size_t namlen;
120 ssize_t extra = -1;
121 struct dirent* entry;
122 struct dirlist* dirstk = 0;
123 struct stat* cur;
124 struct stat* par;
125 struct stat* tmp;
126 struct stat curst;
127 struct stat parst;
128 struct stat tstst;
129 char dots[PATH_MAX];
131 static struct
133 char* name;
134 char* path;
135 dev_t dev;
136 ino_t ino;
137 } env[] =
139 { /*previous*/0 },
140 { "PWD" },
141 { "HOME" },
144 if (buf && !len) ERROR(EINVAL);
145 if (fs3d(FS3D_TEST) && (namlen = mount(".", dots, FS3D_GET|FS3D_VIEW|FS3D_SIZE(sizeof(dots)), NiL)) > 1 && namlen < sizeof(dots))
147 p = dots;
148 easy:
149 namlen++;
150 if (buf)
152 if (len < namlen) ERROR(ERANGE);
154 else if (!(buf = newof(0, char, namlen, len))) ERROR(ENOMEM);
155 return (char*)memcpy(buf, p, namlen);
157 cur = &curst;
158 par = &parst;
159 if (stat(".", par)) ERROR(errno);
160 for (n = 0; n < elementsof(env); n++)
162 if ((env[n].name && (p = getenv(env[n].name)) || (p = env[n].path)) && *p == '/' && !stat(p, cur))
164 env[n].path = p;
165 env[n].dev = cur->st_dev;
166 env[n].ino = cur->st_ino;
167 if (cur->st_ino == par->st_ino && cur->st_dev == par->st_dev)
169 namlen = strlen(p);
170 goto easy;
174 if (!buf)
176 extra = len;
177 len = PATH_MAX;
178 if (!(buf = newof(0, char, len, extra))) ERROR(ENOMEM);
180 d = dots;
181 p = buf + len - 1;
182 *p = 0;
183 n = elementsof(env);
184 for (;;)
186 tmp = cur;
187 cur = par;
188 par = tmp;
189 if ((d - dots) > (PATH_MAX - 4))
191 if (!(dirstk = pushdir(dirstk, dots, p, buf + len - 1))) ERROR(ERANGE);
192 d = dots;
194 *d++ = '.';
195 *d++ = '.';
196 *d = 0;
197 if (!(dirp = opendir(dots))) ERROR(errno);
198 #if !_dir_ok || _mem_dd_fd_DIR
199 if (fstat(dirp->dd_fd, par)) ERROR(errno);
200 #else
201 if (stat(dots, par)) ERROR(errno);
202 #endif
203 *d++ = '/';
204 if (par->st_dev == cur->st_dev)
206 if (par->st_ino == cur->st_ino)
208 closedir(dirp);
209 *--p = '/';
210 pop:
211 if (p != buf)
213 d = buf;
214 while (*d++ = *p++);
215 len = d - buf;
216 if (extra >= 0 && !(buf = newof(buf, char, len, extra))) ERROR(ENOMEM);
218 if (dirstk && popdir(dirstk, buf + len - 1))
220 dirstk = 0;
221 ERROR(errno);
223 if (env[0].path)
224 free(env[0].path);
225 env[0].path = strdup(buf);
226 return buf;
228 #ifdef D_FILENO
229 while (entry = readdir(dirp))
230 if (D_FILENO(entry) == cur->st_ino)
232 namlen = D_NAMLEN(entry);
233 goto found;
235 #endif
238 * this fallthrough handles logical naming
241 rewinddir(dirp);
245 if (!(entry = readdir(dirp))) ERROR(ENOENT);
246 namlen = D_NAMLEN(entry);
247 if ((d - dots) > (PATH_MAX - 1 - namlen))
249 *d = 0;
250 if (namlen >= PATH_MAX || !(dirstk = pushdir(dirstk, dots + 3, p, buf + len - 1))) ERROR(ERANGE);
251 d = dots + 3;
253 memcpy(d, entry->d_name, namlen + 1);
254 } while (stat(dots, &tstst) || tstst.st_ino != cur->st_ino || tstst.st_dev != cur->st_dev);
255 found:
256 if (*p) *--p = '/';
257 while ((p -= namlen) <= (buf + 1))
259 x = (buf + len - 1) - (p += namlen);
260 s = buf + len;
261 if (extra < 0 || !(buf = newof(buf, char, len += PATH_MAX, extra))) ERROR(ERANGE);
262 p = buf + len;
263 while (p > buf + len - 1 - x) *--p = *--s;
265 if (n < elementsof(env))
267 memcpy(p, env[n].path, namlen);
268 goto pop;
270 memcpy(p, entry->d_name, namlen);
271 closedir(dirp);
272 dirp = 0;
273 for (n = 0; n < elementsof(env); n++)
274 if (env[n].ino == par->st_ino && env[n].dev == par->st_dev)
276 namlen = strlen(env[n].path);
277 goto found;
280 error:
281 if (buf)
283 if (dirstk) popdir(dirstk, buf + len - 1);
284 if (extra >= 0) free(buf);
286 if (dirp) closedir(dirp);
287 return 0;
290 #endif