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*
pathprobe(char * path,char * attr,const char * lang,const char * tool,const char * proc,int op)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
rofs(const char * path)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*
pathprobe_20100601(const char * lang,const char * tool,const char * aproc,int op,char * path,size_t pathsize,char * attr,size_t attrsize)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