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