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