1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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  * AT&T Bell Laboratories
25da2e3ebdSchin  * return the real absolute pathname of the preroot dir for cmd
26da2e3ebdSchin  * if cmd==0 then current preroot path returned
27da2e3ebdSchin  */
28da2e3ebdSchin 
29da2e3ebdSchin #include <ast.h>
30da2e3ebdSchin #include <preroot.h>
31da2e3ebdSchin 
32da2e3ebdSchin #if FS_PREROOT
33da2e3ebdSchin 
34da2e3ebdSchin #include <ast_dir.h>
35da2e3ebdSchin #include <ls.h>
36da2e3ebdSchin #include <error.h>
37da2e3ebdSchin #include <stdio.h>
38da2e3ebdSchin 
39da2e3ebdSchin #ifndef ERANGE
40da2e3ebdSchin #define ERANGE		E2BIG
41da2e3ebdSchin #endif
42da2e3ebdSchin 
43da2e3ebdSchin #define ERROR(e)	{errno=e;goto error;}
44da2e3ebdSchin 
45da2e3ebdSchin char*
getpreroot(char * path,const char * cmd)46da2e3ebdSchin getpreroot(char* path, const char* cmd)
47da2e3ebdSchin {
48da2e3ebdSchin 	register int	c;
49da2e3ebdSchin 	register FILE*	fp;
50da2e3ebdSchin 	register char*	p;
51da2e3ebdSchin 	char		buf[PATH_MAX];
52da2e3ebdSchin 
53da2e3ebdSchin 	if (!path) path = buf;
54da2e3ebdSchin 	if (cmd)
55da2e3ebdSchin 	{
56da2e3ebdSchin 		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);
57da2e3ebdSchin 		if (!(fp = popen(buf, "rug"))) return(0);
58da2e3ebdSchin 		for (p = path; (c = getc(fp)) != EOF && c != '\n'; *p++ = c);
59da2e3ebdSchin 		*p = 0;
60da2e3ebdSchin 		pclose(fp);
61da2e3ebdSchin 		if (path == p) return(0);
62da2e3ebdSchin 		return(path == buf ? strdup(path) : path);
63da2e3ebdSchin 	}
64da2e3ebdSchin 	else
65da2e3ebdSchin 	{
66da2e3ebdSchin 		char*		d;
67da2e3ebdSchin 		DIR*		dirp = 0;
68da2e3ebdSchin 		int		namlen;
69da2e3ebdSchin 		int		euid;
70da2e3ebdSchin 		int		ruid;
71da2e3ebdSchin 		struct dirent*	entry;
72da2e3ebdSchin 		struct stat*	cur;
73da2e3ebdSchin 		struct stat*	par;
74da2e3ebdSchin 		struct stat*	tmp;
75da2e3ebdSchin 		struct stat	curst;
76da2e3ebdSchin 		struct stat	parst;
77da2e3ebdSchin 		struct stat	tstst;
78da2e3ebdSchin 		char		dots[PATH_MAX];
79da2e3ebdSchin 
80da2e3ebdSchin 		cur = &curst;
81da2e3ebdSchin 		par = &parst;
82da2e3ebdSchin 		if ((ruid = getuid()) != (euid = geteuid())) setuid(ruid);
83da2e3ebdSchin 		if (stat(PR_REAL, cur) || stat("/", par) || cur->st_dev == par->st_dev && cur->st_ino == par->st_ino) ERROR(ENOTDIR);
84da2e3ebdSchin 
85da2e3ebdSchin 		/*
86da2e3ebdSchin 		 * like getcwd() but starting at the preroot
87da2e3ebdSchin 		 */
88da2e3ebdSchin 
89da2e3ebdSchin 		d = dots;
90da2e3ebdSchin 		*d++ = '/';
91da2e3ebdSchin 		p = path + PATH_MAX - 1;
92da2e3ebdSchin 		*p = 0;
93da2e3ebdSchin 		for (;;)
94da2e3ebdSchin 		{
95da2e3ebdSchin 			tmp = cur;
96da2e3ebdSchin 			cur = par;
97da2e3ebdSchin 			par = tmp;
98da2e3ebdSchin 			if ((d - dots) > (PATH_MAX - 4)) ERROR(ERANGE);
99da2e3ebdSchin 			*d++ = '.';
100da2e3ebdSchin 			*d++ = '.';
101da2e3ebdSchin 			*d = 0;
102da2e3ebdSchin 			if (!(dirp = opendir(dots))) ERROR(errno);
103da2e3ebdSchin #if !_dir_ok || _mem_dd_fd_DIR
104da2e3ebdSchin 			if (fstat(dirp->dd_fd, par)) ERROR(errno);
105da2e3ebdSchin #else
106da2e3ebdSchin 			if (stat(dots, par)) ERROR(errno);
107da2e3ebdSchin #endif
108da2e3ebdSchin 			*d++ = '/';
109da2e3ebdSchin 			if (par->st_dev == cur->st_dev)
110da2e3ebdSchin 			{
111da2e3ebdSchin 				if (par->st_ino == cur->st_ino)
112da2e3ebdSchin 				{
113da2e3ebdSchin 					closedir(dirp);
114da2e3ebdSchin 					*--p = '/';
115da2e3ebdSchin 					if (ruid != euid) setuid(euid);
116da2e3ebdSchin 					if (path == buf) return(strdup(p));
117da2e3ebdSchin 					if (path != p)
118da2e3ebdSchin 					{
119da2e3ebdSchin 						d = path;
120da2e3ebdSchin 						while (*d++ = *p++);
121da2e3ebdSchin 					}
122da2e3ebdSchin 					return(path);
123da2e3ebdSchin 				}
124da2e3ebdSchin #ifdef D_FILENO
125da2e3ebdSchin 				while (entry = readdir(dirp))
126da2e3ebdSchin 					if (D_FILENO(entry) == cur->st_ino)
127da2e3ebdSchin 					{
128da2e3ebdSchin 						namlen = D_NAMLEN(entry);
129da2e3ebdSchin 						goto found;
130da2e3ebdSchin 					}
131da2e3ebdSchin #endif
132da2e3ebdSchin 
133da2e3ebdSchin 				/*
134da2e3ebdSchin 				 * this fallthrough handles logical naming
135da2e3ebdSchin 				 */
136da2e3ebdSchin 
137da2e3ebdSchin 				rewinddir(dirp);
138da2e3ebdSchin 			}
139da2e3ebdSchin 			do
140da2e3ebdSchin 			{
141da2e3ebdSchin 				if (!(entry = readdir(dirp))) ERROR(ENOENT);
142da2e3ebdSchin 				namlen = D_NAMLEN(entry);
143da2e3ebdSchin 				if ((d - dots) > (PATH_MAX - 1 - namlen)) ERROR(ERANGE);
144da2e3ebdSchin 				memcpy(d, entry->d_name, namlen + 1);
145da2e3ebdSchin 				if (stat(dots, &tstst)) ERROR(errno);
146da2e3ebdSchin 			} while (tstst.st_ino != cur->st_ino || tstst.st_dev != cur->st_dev);
147da2e3ebdSchin 		found:
148da2e3ebdSchin 			if (*p) *--p = '/';
149da2e3ebdSchin 			if ((p -= namlen) <= (path + 1)) ERROR(ERANGE);
150da2e3ebdSchin 			memcpy(p, entry->d_name, namlen);
151da2e3ebdSchin 			closedir(dirp);
152da2e3ebdSchin 			dirp = 0;
153da2e3ebdSchin 		}
154da2e3ebdSchin 	error:
155da2e3ebdSchin 		if (dirp) closedir(dirp);
156da2e3ebdSchin 		if (ruid != euid) setuid(euid);
157da2e3ebdSchin 	}
158da2e3ebdSchin 	return(0);
159da2e3ebdSchin }
160da2e3ebdSchin 
161da2e3ebdSchin #else
162da2e3ebdSchin 
163da2e3ebdSchin NoN(getpreroot)
164da2e3ebdSchin 
165da2e3ebdSchin #endif
166