xref: /onnv-gate/usr/src/lib/libast/common/misc/getcwd.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin /*
244887Schin  * Glenn Fowler
254887Schin  * AT&T Research
264887Schin  *
274887Schin  * pwd library support
284887Schin  */
294887Schin 
304887Schin #include <ast.h>
314887Schin 
324887Schin #if _WINIX
334887Schin 
344887Schin NoN(getcwd)
354887Schin 
364887Schin #else
374887Schin 
384887Schin #include <ast_dir.h>
394887Schin #include <error.h>
404887Schin #include <fs3d.h>
414887Schin 
424887Schin #ifndef ERANGE
434887Schin #define ERANGE		E2BIG
444887Schin #endif
454887Schin 
464887Schin #define ERROR(e)	{ errno = e; goto error; }
474887Schin 
484887Schin struct dirlist				/* long path chdir(2) component	*/
494887Schin {
504887Schin 	struct dirlist*	next;		/* next component		*/
514887Schin 	int		index;		/* index from end of buf	*/
524887Schin };
534887Schin 
544887Schin /*
554887Schin  * pop long dir component chdir stack
564887Schin  */
574887Schin 
584887Schin static int
594887Schin popdir(register struct dirlist* d, register char* end)
604887Schin {
614887Schin 	register struct dirlist*	dp;
624887Schin 	int				v;
634887Schin 
644887Schin 	v = 0;
654887Schin 	while (dp = d)
664887Schin 	{
674887Schin 		d = d->next;
684887Schin 		if (!v)
694887Schin 		{
704887Schin 			if (d) *(end - d->index - 1) = 0;
714887Schin 			v = chdir(end - dp->index);
724887Schin 			if (d) *(end - d->index - 1) = '/';
734887Schin 		}
744887Schin 		free(dp);
754887Schin 	}
764887Schin 	return v;
774887Schin }
784887Schin 
794887Schin /*
804887Schin  * push long dir component onto stack
814887Schin  */
824887Schin 
834887Schin static struct dirlist*
844887Schin pushdir(register struct dirlist* d, char* dots, char* path, char* end)
854887Schin {
864887Schin 	register struct dirlist*	p;
874887Schin 
884887Schin 	if (!(p = newof(0, struct dirlist, 1, 0)) || chdir(dots))
894887Schin 	{
904887Schin 		if (p) free(p);
914887Schin 		if (d) popdir(d, end);
924887Schin 		return 0;
934887Schin 	}
944887Schin 	p->index = end - path;
954887Schin 	p->next = d;
964887Schin 	return p;
974887Schin }
984887Schin 
994887Schin /*
1004887Schin  * return a pointer to the absolute path name of .
1014887Schin  * this path name may be longer than PATH_MAX
1024887Schin  *
1034887Schin  * a few environment variables are checked before the search algorithm
1044887Schin  * return value is placed in buf of len chars
1054887Schin  * if buf is 0 then space is allocated via malloc() with
1064887Schin  * len extra chars after the path name
1074887Schin  * 0 is returned on error with errno set as appropriate
1084887Schin  */
1094887Schin 
1104887Schin char*
1114887Schin getcwd(char* buf, size_t len)
1124887Schin {
1134887Schin 	register char*	d;
1144887Schin 	register char*	p;
1154887Schin 	register char*	s;
1164887Schin 	DIR*		dirp = 0;
1174887Schin 	int		n;
1184887Schin 	int		x;
1194887Schin 	size_t		namlen;
1204887Schin 	ssize_t		extra = -1;
1214887Schin 	struct dirent*	entry;
1224887Schin 	struct dirlist*	dirstk = 0;
1234887Schin 	struct stat*	cur;
1244887Schin 	struct stat*	par;
1254887Schin 	struct stat*	tmp;
1264887Schin 	struct stat	curst;
1274887Schin 	struct stat	parst;
1284887Schin 	struct stat	tstst;
1294887Schin 	char		dots[PATH_MAX];
1304887Schin 
1314887Schin 	static struct
1324887Schin 	{
1334887Schin 		char*	name;
1344887Schin 		char*	path;
1354887Schin 		dev_t	dev;
1364887Schin 		ino_t	ino;
1374887Schin 	}		env[] =
1384887Schin 	{
1394887Schin 		{ /*previous*/0	},
1404887Schin 		{ "PWD"		},
1414887Schin 		{ "HOME"	},
1424887Schin 	};
1434887Schin 
1444887Schin 	if (buf && !len) ERROR(EINVAL);
1454887Schin 	if (fs3d(FS3D_TEST) && (namlen = mount(".", dots, FS3D_GET|FS3D_VIEW|FS3D_SIZE(sizeof(dots)), NiL)) > 1 && namlen < sizeof(dots))
1464887Schin 	{
1474887Schin 		p = dots;
1484887Schin 	easy:
1494887Schin 		namlen++;
1504887Schin 		if (buf)
1514887Schin 		{
1524887Schin 			if (len < namlen) ERROR(ERANGE);
1534887Schin 		}
1544887Schin 		else if (!(buf = newof(0, char, namlen, len))) ERROR(ENOMEM);
1554887Schin 		return (char*)memcpy(buf, p, namlen);
1564887Schin 	}
1574887Schin 	cur = &curst;
1584887Schin 	par = &parst;
1594887Schin 	if (stat(".", par)) ERROR(errno);
1604887Schin 	for (n = 0; n < elementsof(env); n++)
1614887Schin 	{
1624887Schin 		if ((env[n].name && (p = getenv(env[n].name)) || (p = env[n].path)) && *p == '/' && !stat(p, cur))
1634887Schin 		{
1644887Schin 			env[n].path = p;
1654887Schin 			env[n].dev = cur->st_dev;
1664887Schin 			env[n].ino = cur->st_ino;
1674887Schin 			if (cur->st_ino == par->st_ino && cur->st_dev == par->st_dev)
1684887Schin 			{
1694887Schin 				namlen = strlen(p);
1704887Schin 				goto easy;
1714887Schin 			}
1724887Schin 		}
1734887Schin 	}
1744887Schin 	if (!buf)
1754887Schin 	{
1764887Schin 		extra = len;
1774887Schin 		len = PATH_MAX;
1784887Schin 		if (!(buf = newof(0, char, len, extra))) ERROR(ENOMEM);
1794887Schin 	}
1804887Schin 	d = dots;
1814887Schin 	p = buf + len - 1;
1824887Schin 	*p = 0;
1834887Schin 	n = elementsof(env);
1844887Schin 	for (;;)
1854887Schin 	{
1864887Schin 		tmp = cur;
1874887Schin 		cur = par;
1884887Schin 		par = tmp;
1894887Schin 		if ((d - dots) > (PATH_MAX - 4))
1904887Schin 		{
1914887Schin 			if (!(dirstk = pushdir(dirstk, dots, p, buf + len - 1))) ERROR(ERANGE);
1924887Schin 			d = dots;
1934887Schin 		}
1944887Schin 		*d++ = '.';
1954887Schin 		*d++ = '.';
1964887Schin 		*d = 0;
1974887Schin 		if (!(dirp = opendir(dots))) ERROR(errno);
1984887Schin #if !_dir_ok || _mem_dd_fd_DIR
1994887Schin 		if (fstat(dirp->dd_fd, par)) ERROR(errno);
2004887Schin #else
2014887Schin 		if (stat(dots, par)) ERROR(errno);
2024887Schin #endif
2034887Schin 		*d++ = '/';
2044887Schin 		if (par->st_dev == cur->st_dev)
2054887Schin 		{
2064887Schin 			if (par->st_ino == cur->st_ino)
2074887Schin 			{
2084887Schin 				closedir(dirp);
2094887Schin 				*--p = '/';
2104887Schin 			pop:
2114887Schin 				if (p != buf)
2124887Schin 				{
2134887Schin 					d = buf;
2144887Schin 					while (*d++ = *p++);
2154887Schin 					len = d - buf;
2164887Schin 					if (extra >= 0 && !(buf = newof(buf, char, len, extra))) ERROR(ENOMEM);
2174887Schin 				}
2184887Schin 				if (dirstk && popdir(dirstk, buf + len - 1))
2194887Schin 				{
2204887Schin 					dirstk = 0;
2214887Schin 					ERROR(errno);
2224887Schin 				}
2234887Schin 				if (env[0].path)
2244887Schin 					free(env[0].path);
2254887Schin 				env[0].path = strdup(buf);
2264887Schin 				return buf;
2274887Schin 			}
2284887Schin #ifdef D_FILENO
2294887Schin 			while (entry = readdir(dirp))
2304887Schin 				if (D_FILENO(entry) == cur->st_ino)
2314887Schin 				{
2324887Schin 					namlen = D_NAMLEN(entry);
2334887Schin 					goto found;
2344887Schin 				}
2354887Schin #endif
2364887Schin 
2374887Schin 			/*
2384887Schin 			 * this fallthrough handles logical naming
2394887Schin 			 */
2404887Schin 
2414887Schin 			rewinddir(dirp);
2424887Schin 		}
2434887Schin 		do
2444887Schin 		{
2454887Schin 			if (!(entry = readdir(dirp))) ERROR(ENOENT);
2464887Schin 			namlen = D_NAMLEN(entry);
2474887Schin 			if ((d - dots) > (PATH_MAX - 1 - namlen))
2484887Schin 			{
2494887Schin 				*d = 0;
2504887Schin 				if (namlen >= PATH_MAX || !(dirstk = pushdir(dirstk, dots + 3, p, buf + len - 1))) ERROR(ERANGE);
2514887Schin 				d = dots + 3;
2524887Schin 			}
2534887Schin 			memcpy(d, entry->d_name, namlen + 1);
2544887Schin 		} while (stat(dots, &tstst) || tstst.st_ino != cur->st_ino || tstst.st_dev != cur->st_dev);
2554887Schin 	found:
2564887Schin 		if (*p) *--p = '/';
2574887Schin 		while ((p -= namlen) <= (buf + 1))
2584887Schin 		{
2594887Schin 			x = (buf + len - 1) - (p += namlen);
2604887Schin 			s = buf + len;
2614887Schin 			if (extra < 0 || !(buf = newof(buf, char, len += PATH_MAX, extra))) ERROR(ERANGE);
2624887Schin 			p = buf + len;
2634887Schin 			while (p > buf + len - 1 - x) *--p = *--s;
2644887Schin 		}
2654887Schin 		if (n < elementsof(env))
2664887Schin 		{
2674887Schin 			memcpy(p, env[n].path, namlen);
2684887Schin 			goto pop;
2694887Schin 		}
2704887Schin 		memcpy(p, entry->d_name, namlen);
2714887Schin 		closedir(dirp);
2724887Schin 		dirp = 0;
2734887Schin 		for (n = 0; n < elementsof(env); n++)
2744887Schin 			if (env[n].ino == par->st_ino && env[n].dev == par->st_dev)
2754887Schin 			{
2764887Schin 				namlen = strlen(env[n].path);
2774887Schin 				goto found;
2784887Schin 			}
2794887Schin 	}
2804887Schin  error:
2814887Schin 	if (buf)
2824887Schin 	{
2834887Schin 		if (dirstk) popdir(dirstk, buf + len - 1);
2844887Schin 		if (extra >= 0) free(buf);
2854887Schin 	}
2864887Schin 	if (dirp) closedir(dirp);
2874887Schin 	return 0;
2884887Schin }
2894887Schin 
2904887Schin #endif
291