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