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