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