1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 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
rofs(const char * path)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*
pathprobe(char * path,char * attr,const char * lang,const char * tool,const char * aproc,int op)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