xref: /titanic_44/usr/src/lib/libast/common/path/pathprobe.c (revision 2d6b5ea734bb47d251c82670646fde46af15fd69)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2008 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
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  * Glenn Fowler
25  * AT&T Research
26  *
27  * return in path the full path name of the probe(1)
28  * information for lang and tool using proc
29  * if attr != 0 then path attribute assignments placed here
30  *
31  * if path==0 then the space is malloc'd
32  *
33  * op:
34  *
35  *	-3	return non-writable path name with no generation
36  *	-2	return path name with no generation
37  *	-1	return no $HOME path name with no generation
38  *	0	verbose probe
39  *	1	silent probe
40  *
41  * 0 returned if the info does not exist and cannot be generated
42  */
43 
44 #include <ast.h>
45 #include <error.h>
46 #include <ls.h>
47 #include <proc.h>
48 
49 #ifndef PROBE
50 #define PROBE		"probe"
51 #endif
52 
53 #if defined(ST_RDONLY) || defined(ST_NOSUID)
54 
55 /*
56  * return non-0 if path is in a readonly or non-setuid fs
57  */
58 
59 static int
60 rofs(const char* path)
61 {
62 	struct statvfs	vfs;
63 	struct stat	st;
64 
65 	if (!statvfs(path, &vfs))
66 	{
67 #if defined(ST_RDONLY)
68 		if (vfs.f_flag & ST_RDONLY)
69 			return 1;
70 #endif
71 #if defined(ST_NOSUID)
72 		if ((vfs.f_flag & ST_NOSUID) && (stat(path, &st) || st.st_uid != getuid() && st.st_uid != geteuid()))
73 			return 1;
74 #endif
75 	}
76 	return 0;
77 }
78 
79 #else
80 
81 #define rofs(p)		0
82 
83 #endif
84 
85 char*
86 pathprobe(char* path, char* attr, const char* lang, const char* tool, const char* aproc, int op)
87 {
88 	char*		proc = (char*)aproc;
89 	register char*	p;
90 	register char*	k;
91 	register char*	x;
92 	register char**	ap;
93 	int		n;
94 	int		v;
95 	int		force;
96 	ssize_t		r;
97 	char*		e;
98 	char*		np;
99 	char*		nx;
100 	char*		probe;
101 	const char*	dirs;
102 	const char*	dir;
103 	Proc_t*		pp;
104 	Sfio_t*		sp;
105 	char		buf[PATH_MAX];
106 	char		cmd[PATH_MAX];
107 	char		exe[PATH_MAX];
108 	char		lib[PATH_MAX];
109 	char		ver[PATH_MAX];
110 	char		key[16];
111 	char*		arg[8];
112 	long		ops[2];
113 	unsigned long	ptime;
114 	struct stat	st;
115 	struct stat	ps;
116 
117 	if (*proc != '/')
118 	{
119 		if (p = strchr(proc, ' '))
120 		{
121 			strncopy(buf, proc, p - proc + 1);
122 			proc = buf;
123 		}
124 		if (!(proc = pathpath(cmd, proc, NiL, PATH_ABSOLUTE|PATH_REGULAR|PATH_EXECUTE)))
125 			proc = (char*)aproc;
126 		else if (p)
127 		{
128 			n = strlen(proc);
129 			strncopy(proc + n, p, PATH_MAX - n - 1);
130 		}
131 	}
132 	if (!path)
133 		path = buf;
134 	probe = PROBE;
135 	x = lib + sizeof(lib) - 1;
136 	k = lib + sfsprintf(lib, x - lib, "lib/%s/", probe);
137 	p = k + sfsprintf(k, x - k, "%s/%s/", lang, tool);
138 	pathkey(key, attr, lang, tool, proc);
139 	if (op >= -2)
140 	{
141 		strncopy(p, key, x - p);
142 		if (pathpath(path, lib, "", PATH_ABSOLUTE) && !stat(path, &st) && (st.st_mode & S_IWUSR))
143 			return path == buf ? strdup(path) : path;
144 	}
145 	e = strncopy(p, probe, x - p);
146 	if (!pathpath(path, lib, "", PATH_ABSOLUTE|PATH_EXECUTE) || stat(path, &ps))
147 		return 0;
148 	for (;;)
149 	{
150 		ptime = ps.st_mtime;
151 		n = strlen(path);
152 		if (n < (PATH_MAX - 5))
153 		{
154 			strcpy(path + n, ".ini");
155 			if (!stat(path, &st) && st.st_size && ptime < (unsigned long)st.st_mtime)
156 				ptime = st.st_mtime;
157 			path[n] = 0;
158 		}
159 		np = path + n - (e - k);
160 		nx = path + PATH_MAX - 1;
161 		strncopy(np, probe, nx - np);
162 		if (!stat(path, &st))
163 			break;
164 
165 		/*
166 		 * yes lib/probe/<lang>/<proc>/probe
167 		 *  no lib/probe/probe
168 		 *
169 		 * do a manual pathaccess() to find a dir with both
170 		 */
171 
172 		sfsprintf(exe, sizeof(exe), "lib/%s/%s", probe, probe);
173 		dirs = pathbin();
174 		for (;;)
175 		{
176 			if (!(dir = dirs))
177 				return 0;
178 			dirs = pathcat(path, dir, ':', "..", exe);
179 			pathcanon(path, 0);
180 			if (*path == '/' && pathexists(path, PATH_REGULAR|PATH_EXECUTE))
181 			{
182 				pathcat(path, dir, ':', "..", lib);
183 				pathcanon(path, 0);
184 				if (*path == '/' && pathexists(path, PATH_REGULAR|PATH_EXECUTE) && !stat(path, &ps))
185 					break;
186 			}
187 		}
188 	}
189 	strncopy(p, key, x - p);
190 	p = np;
191 	x = nx;
192 	strcpy(exe, path);
193 	if (op >= -1 && (!(st.st_mode & S_ISUID) && ps.st_uid != geteuid() || rofs(path)))
194 	{
195 		if (!(p = getenv("HOME")))
196 			return 0;
197 		p = path + sfsprintf(path, PATH_MAX - 1, "%s/.%s/%s/", p, probe, HOSTTYPE);
198 	}
199 	strncopy(p, k, x - p);
200 	force = 0;
201 	if (op >= 0 && !stat(path, &st))
202 	{
203 		if (ptime <= (unsigned long)st.st_mtime || ptime <= (unsigned long)st.st_ctime)
204 		{
205 			/*
206 			 * verify (<sep><name><sep><option><sep><value>)* header
207 			 */
208 
209 			if (sp = sfopen(NiL, path, "r"))
210 			{
211 				if (x = sfgetr(sp, '\n', 1))
212 				{
213 					while (*x && *x != ' ')
214 						x++;
215 					while (*x == ' ')
216 						x++;
217 					if (n = *x++)
218 						for (;;)
219 						{
220 							for (k = x; *x && *x != n; x++);
221 							if (!*x)
222 								break;
223 							*x++ = 0;
224 							for (p = x; *x && *x != n; x++);
225 							if (!*x)
226 								break;
227 							*x++ = 0;
228 							for (e = x; *x && *x != n; x++);
229 							if (!*x)
230 								break;
231 							*x++ = 0;
232 							if (streq(k, "VERSION"))
233 							{
234 								ap = arg;
235 								*ap++ = proc;
236 								*ap++ = p;
237 								*ap = 0;
238 								ops[0] =  PROC_FD_DUP(1, 2, 0);
239 								ops[1] = 0;
240 								if (pp = procopen(proc, arg, NiL, ops, PROC_READ))
241 								{
242 									if ((v = x - e) >= sizeof(ver))
243 										v = sizeof(ver) - 1;
244 									for (k = p = ver;; k++)
245 									{
246 										if (k >= p)
247 										{
248 											if (v <= 0 || (r = read(pp->rfd, k, v)) <= 0)
249 												break;
250 											v -= r;
251 											p = k + r;
252 										}
253 										if (*k == '\n' || *k == '\r')
254 											break;
255 										if (*k == n)
256 											*k = ' ';
257 									}
258 									*k = 0;
259 									if (strcmp(ver, e))
260 									{
261 										force = 1;
262 										error(0, "probe processor %s version \"%s\" changed -- expected \"%s\"", proc, ver, e);
263 									}
264 									procclose(pp);
265 								}
266 								break;
267 							}
268 						}
269 				}
270 				sfclose(sp);
271 			}
272 			if (!force)
273 				op = -1;
274 		}
275 		if (op >= 0 && (st.st_mode & S_IWUSR))
276 		{
277 			if (op == 0)
278 				error(0, "%s probe information for %s language processor %s must be manually regenerated", tool, lang, proc);
279 			op = -1;
280 			force = 0;
281 		}
282 	}
283 	if (op >= 0)
284 	{
285 		ap = arg;
286 		*ap++ = exe;
287 		if (force)
288 			*ap++ = "-f";
289 		if (op > 0)
290 			*ap++ = "-s";
291 		*ap++ = (char*)lang;
292 		*ap++ = (char*)tool;
293 		*ap++ = proc;
294 		*ap = 0;
295 		if (procrun(exe, arg, 0))
296 			return 0;
297 		if (eaccess(path, R_OK))
298 			return 0;
299 	}
300 	return path == buf ? strdup(path) : path;
301 }
302