xref: /titanic_41/usr/src/lib/libast/common/preroot/getpreroot.c (revision d29b2c4438482eb00488be49a1f5d6835f455546)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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 
45 char*
46 getpreroot(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 
163 NoN(getpreroot)
164 
165 #endif
166