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