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 * AT&T Bell Laboratories
254887Schin * return the real absolute pathname of the preroot dir for cmd
264887Schin * if cmd==0 then current preroot path returned
274887Schin */
284887Schin
294887Schin #include <ast.h>
304887Schin #include <preroot.h>
314887Schin
324887Schin #if FS_PREROOT
334887Schin
344887Schin #include <ast_dir.h>
354887Schin #include <ls.h>
364887Schin #include <error.h>
374887Schin #include <stdio.h>
384887Schin
394887Schin #ifndef ERANGE
404887Schin #define ERANGE E2BIG
414887Schin #endif
424887Schin
434887Schin #define ERROR(e) {errno=e;goto error;}
444887Schin
454887Schin char*
getpreroot(char * path,const char * cmd)464887Schin getpreroot(char* path, const char* cmd)
474887Schin {
484887Schin register int c;
494887Schin register FILE* fp;
504887Schin register char* p;
514887Schin char buf[PATH_MAX];
524887Schin
534887Schin if (!path) path = buf;
544887Schin if (cmd)
554887Schin {
564887Schin sfsprintf(buf, sizeof(buf), "set x `%s= %s - </dev/null 2>&1`\nwhile :\ndo\nshift\ncase $# in\n[012]) break ;;\nesac\ncase \"$1 $2\" in\n\"+ %s\") echo $3; exit ;;\nesac\ndone\necho\n", PR_SILENT, cmd, PR_COMMAND);
574887Schin if (!(fp = popen(buf, "rug"))) return(0);
584887Schin for (p = path; (c = getc(fp)) != EOF && c != '\n'; *p++ = c);
594887Schin *p = 0;
604887Schin pclose(fp);
614887Schin if (path == p) return(0);
624887Schin return(path == buf ? strdup(path) : path);
634887Schin }
644887Schin else
654887Schin {
664887Schin char* d;
674887Schin DIR* dirp = 0;
684887Schin int namlen;
694887Schin int euid;
704887Schin int ruid;
714887Schin struct dirent* entry;
724887Schin struct stat* cur;
734887Schin struct stat* par;
744887Schin struct stat* tmp;
754887Schin struct stat curst;
764887Schin struct stat parst;
774887Schin struct stat tstst;
784887Schin char dots[PATH_MAX];
794887Schin
804887Schin cur = &curst;
814887Schin par = &parst;
824887Schin if ((ruid = getuid()) != (euid = geteuid())) setuid(ruid);
834887Schin if (stat(PR_REAL, cur) || stat("/", par) || cur->st_dev == par->st_dev && cur->st_ino == par->st_ino) ERROR(ENOTDIR);
844887Schin
854887Schin /*
864887Schin * like getcwd() but starting at the preroot
874887Schin */
884887Schin
894887Schin d = dots;
904887Schin *d++ = '/';
914887Schin p = path + PATH_MAX - 1;
924887Schin *p = 0;
934887Schin for (;;)
944887Schin {
954887Schin tmp = cur;
964887Schin cur = par;
974887Schin par = tmp;
984887Schin if ((d - dots) > (PATH_MAX - 4)) ERROR(ERANGE);
994887Schin *d++ = '.';
1004887Schin *d++ = '.';
1014887Schin *d = 0;
1024887Schin if (!(dirp = opendir(dots))) ERROR(errno);
1034887Schin #if !_dir_ok || _mem_dd_fd_DIR
1044887Schin if (fstat(dirp->dd_fd, par)) ERROR(errno);
1054887Schin #else
1064887Schin if (stat(dots, par)) ERROR(errno);
1074887Schin #endif
1084887Schin *d++ = '/';
1094887Schin if (par->st_dev == cur->st_dev)
1104887Schin {
1114887Schin if (par->st_ino == cur->st_ino)
1124887Schin {
1134887Schin closedir(dirp);
1144887Schin *--p = '/';
1154887Schin if (ruid != euid) setuid(euid);
1164887Schin if (path == buf) return(strdup(p));
1174887Schin if (path != p)
1184887Schin {
1194887Schin d = path;
1204887Schin while (*d++ = *p++);
1214887Schin }
1224887Schin return(path);
1234887Schin }
1244887Schin #ifdef D_FILENO
1254887Schin while (entry = readdir(dirp))
1264887Schin if (D_FILENO(entry) == cur->st_ino)
1274887Schin {
1284887Schin namlen = D_NAMLEN(entry);
1294887Schin goto found;
1304887Schin }
1314887Schin #endif
1324887Schin
1334887Schin /*
1344887Schin * this fallthrough handles logical naming
1354887Schin */
1364887Schin
1374887Schin rewinddir(dirp);
1384887Schin }
1394887Schin do
1404887Schin {
1414887Schin if (!(entry = readdir(dirp))) ERROR(ENOENT);
1424887Schin namlen = D_NAMLEN(entry);
1434887Schin if ((d - dots) > (PATH_MAX - 1 - namlen)) ERROR(ERANGE);
1444887Schin memcpy(d, entry->d_name, namlen + 1);
1454887Schin if (stat(dots, &tstst)) ERROR(errno);
1464887Schin } while (tstst.st_ino != cur->st_ino || tstst.st_dev != cur->st_dev);
1474887Schin found:
1484887Schin if (*p) *--p = '/';
1494887Schin if ((p -= namlen) <= (path + 1)) ERROR(ERANGE);
1504887Schin memcpy(p, entry->d_name, namlen);
1514887Schin closedir(dirp);
1524887Schin dirp = 0;
1534887Schin }
1544887Schin error:
1554887Schin if (dirp) closedir(dirp);
1564887Schin if (ruid != euid) setuid(euid);
1574887Schin }
1584887Schin return(0);
1594887Schin }
1604887Schin
1614887Schin #else
1624887Schin
1634887Schin NoN(getpreroot)
1644887Schin
1654887Schin #endif
166