1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1989-2011 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 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * Glenn Fowler
23 * AT&T Research
24 *
25 * process status stream implementation
26 */
27
28 static const char id[] = "\n@(#)$Id: pss library (AT&T Research) 2011-05-09 $\0\n";
29
30 static const char lib[] = "std:pss";
31
32 #include "psslib.h"
33
34 #define TTYMAP(p,d) ((p)->meth->ttymapf?(*(p)->meth->ttymapf)(p,d):(d))
35
36 /*
37 * open a pss stream
38 */
39
40 Pss_t*
pssopen(Pssdisc_t * disc)41 pssopen(Pssdisc_t* disc)
42 {
43 register Pss_t* pss;
44 Vmalloc_t* vm;
45
46 if (!disc)
47 return 0;
48 if (!(vm = vmopen(Vmdcheap, Vmbest, 0)) || !(pss = vmnewof(vm, 0, Pss_t, 1, 0)))
49 goto bad;
50 pss->id = lib;
51 pss->disc = disc;
52 pss->vm = vm;
53 pss->ttybynamedisc.key = offsetof(Tty_t, name);
54 pss->ttybynamedisc.size = 0;
55 pss->ttybynamedisc.link = offsetof(Tty_t, byname);
56 pss->ttybydevdisc.key = offsetof(Tty_t, dev);
57 pss->ttybydevdisc.size = sizeof(Pss_dev_t);
58 pss->ttybydevdisc.link = offsetof(Tty_t, bydev);
59 if (!(pss->ttybyname = dtnew(pss->vm, &pss->ttybynamedisc, Dtset)) ||
60 !(pss->ttybydev = dtnew(pss->vm, &pss->ttybydevdisc, Dtset)))
61 goto bad;
62 pss->meth = (_pss_ps && ((disc->flags & PSS_PS) || getenv("_PSS_ps"))) ? _pss_ps : _pss_method;
63 while (pss->meth->initf && (*pss->meth->initf)(pss) <= 0)
64 if (pss->meth == _pss_ps || !(pss->meth = _pss_ps))
65 {
66 vmclose(vm);
67 return 0;
68 }
69 return pss;
70 bad:
71 if (disc->errorf)
72 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
73 if (vm)
74 vmclose(vm);
75 return 0;
76 }
77
78 /*
79 * close a pss stream
80 */
81
82 int
pssclose(Pss_t * pss)83 pssclose(Pss_t* pss)
84 {
85 int r;
86
87 if (!pss || !pss->vm)
88 return -1;
89 r = (pss->meth->donef && (*pss->meth->donef)(pss) <= 0) ? -1 : 0;
90 if ((pss->disc->flags & PSS_VERBOSE) && pss->disc->errorf)
91 (*pss->disc->errorf)(pss, pss->disc, 1, "%s: method done", pss->meth->name);
92 vmclose(pss->vm);
93 return r;
94 }
95
96 /*
97 * return the pss entry for pid
98 * if pid==0 then return the next pid
99 */
100
101 Pssent_t*
pssread(register Pss_t * pss,Pss_id_t pid)102 pssread(register Pss_t* pss, Pss_id_t pid)
103 {
104 register unsigned long fields = pss->meth->fields;
105 register unsigned long flags = pss->disc->flags;
106 register Pssent_t* pe;
107 Pssmatch_t* mp;
108 Pssdata_t* dp;
109 unsigned long x;
110 int i;
111
112 for (;;)
113 {
114 if ((*pss->meth->readf)(pss, pid) <= 0)
115 return 0;
116 if (!pss->ent && !(pss->ent = vmnewof(pss->vm, 0, Pssent_t, 1, 0)))
117 {
118 if (pss->disc->errorf)
119 (*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "out of space");
120 return 0;
121 }
122 pe = pss->ent;
123 if ((i = (*pss->meth->partf)(pss, pe)) < 0)
124 return 0;
125 if (!i)
126 {
127 memset(pe, 0, sizeof(*pe));
128 pe->pid = pss->pid;
129 goto next;
130 }
131 if (pid)
132 pe->pss = PSS_EXPLICIT;
133 else if (flags & PSS_ALL)
134 pe->pss = PSS_MATCHED;
135 else
136 {
137 if (flags & (PSS_ATTACHED|PSS_DETACHED|PSS_LEADER|PSS_NOLEADER|PSS_TTY|PSS_UID))
138 {
139 if ((flags & PSS_TTY) && pe->tty != TTYMAP(pss, pss->disc->tty))
140 goto next;
141 if ((flags & PSS_UID) && pe->uid != pss->disc->uid)
142 goto next;
143 switch (flags & (PSS_ATTACHED|PSS_DETACHED))
144 {
145 case PSS_ATTACHED:
146 if (pe->tty == PSS_NODEV)
147 goto next;
148 break;
149 case PSS_DETACHED:
150 if (pe->tty != PSS_NODEV)
151 goto next;
152 break;
153 }
154 switch (flags & (PSS_LEADER|PSS_NOLEADER))
155 {
156 case PSS_LEADER:
157 if ((fields & PSS_sid) && pe->pid != pe->sid)
158 goto next;
159 if ((fields & PSS_tgrp) && pe->pid != pe->tgrp)
160 goto next;
161 break;
162 case PSS_NOLEADER:
163 if ((fields & PSS_sid) && pe->pid == pe->sid)
164 goto next;
165 if ((fields & PSS_tgrp) && pe->pid == pe->tgrp)
166 goto next;
167 break;
168 }
169 pe->pss = PSS_MATCHED;
170 }
171 if (mp = pss->disc->match)
172 {
173 do
174 {
175 switch (mp->field)
176 {
177 case PSS_gid:
178 x = pe->gid;
179 break;
180 case PSS_pgrp:
181 x = pe->pgrp;
182 break;
183 case PSS_sid:
184 x = pe->sid;
185 break;
186 case PSS_tgrp:
187 x = pe->tgrp;
188 break;
189 case PSS_tty:
190 x = pe->tty;
191 if (pss->meth->ttymapf)
192 for (dp = mp->data; dp; dp = dp->next)
193 dp->data = TTYMAP(pss, dp->data);
194 break;
195 case PSS_uid:
196 x = pe->uid;
197 break;
198 default:
199 if (pss->disc->errorf)
200 (*pss->disc->errorf)(pss, pss->disc, 2, "%08lx selection not implemented", mp->field);
201 return 0;
202 }
203 for (dp = mp->data; dp; dp = dp->next)
204 if (dp->data == x)
205 break;
206 } while (!dp && (mp = mp->next));
207 if (!mp)
208 goto next;
209 pe->pss = PSS_MATCHED;
210 }
211 }
212 break;
213 next:
214 if (flags & PSS_UNMATCHED)
215 {
216 pe->pss = 0;
217 break;
218 }
219 if (pid)
220 return 0;
221 }
222 if (pss->meth->fullf && (*pss->meth->fullf)(pss, pe) <= 0)
223 return 0;
224 if (pe->pid <= 1 && pe->ppid > 1)
225 {
226 pe->ppid = 0;
227 if (pe->pid == 0)
228 pe->args = pe->command = "sched";
229 }
230 return pe;
231 }
232
233 /*
234 * save entry data
235 */
236
237 Pssent_t*
psssave(register Pss_t * pss,register Pssent_t * pe)238 psssave(register Pss_t* pss, register Pssent_t* pe)
239 {
240 register unsigned long fields = pss->disc->fields & pss->meth->fields;
241
242 if ((fields & PSS_args) && pe->args)
243 pe->args = vmstrdup(pss->vm, pe->args);
244 if ((fields & PSS_command) && pe->command)
245 pe->command = vmstrdup(pss->vm, pe->command);
246 if ((fields & PSS_sched) && pe->sched)
247 pe->sched = vmstrdup(pss->vm, pe->sched);
248 if ((fields & PSS_tty) && pe->ttyname)
249 pe->ttyname = vmstrdup(pss->vm, pe->ttyname);
250 pss->ent = 0;
251 return pe;
252 }
253
254 /*
255 * add name,dev to the tty hash
256 */
257
258 int
pssttyadd(register Pss_t * pss,const char * name,Pss_dev_t dev)259 pssttyadd(register Pss_t* pss, const char* name, Pss_dev_t dev)
260 {
261 register Tty_t* tty;
262
263 if (!dtmatch(pss->ttybyname, name))
264 {
265 if (!(tty = vmnewof(pss->vm, 0, Tty_t, 1, strlen(name))))
266 {
267 if (pss->disc->errorf)
268 (*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "out of space");
269 return -1;
270 }
271 strcpy(tty->name, name);
272 tty->dev = dev;
273 dtinsert(pss->ttybyname, tty);
274 if (!dtmatch(pss->ttybydev, &dev))
275 dtinsert(pss->ttybydev, tty);
276 }
277 return 0;
278 }
279
280 /*
281 * scan /dev and enter in the tty hash
282 */
283
284 static void
ttyscan(register Pss_t * pss)285 ttyscan(register Pss_t* pss)
286 {
287 register DIR* dir;
288 register struct dirent* ent;
289 DIR* sub = 0;
290 char* base;
291 char* name;
292 struct stat st;
293 char path[PATH_MAX];
294
295 pss->ttyscan = 1;
296 strcpy(path, "/dev");
297 if (!(dir = opendir(path)))
298 {
299 if (pss->disc->errorf)
300 (*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "%s: cannot read", path);
301 return;
302 }
303 path[4] = '/';
304 name = base = path + 5;
305 for (;;)
306 {
307 while (ent = readdir(dir))
308 {
309 if (D_NAMLEN(ent) + (base - path) + 1 > sizeof(path))
310 continue;
311 if (!sub && (ent->d_name[0] != 'c' && ent->d_name[0] != 't' && ent->d_name[0] != 'p' && ent->d_name[0] != 'v' || ent->d_name[1] != 'o' && ent->d_name[1] != 't'))
312 continue;
313 strcpy(base, ent->d_name);
314 if (stat(path, &st))
315 continue;
316 if (!S_ISCHR(st.st_mode))
317 {
318 if (sub || !S_ISDIR(st.st_mode))
319 continue;
320 sub = dir;
321 if (dir = opendir(path))
322 {
323 base = path + strlen(path);
324 *base++ = '/';
325 }
326 else
327 {
328 dir = sub;
329 sub = 0;
330 }
331 continue;
332 }
333 if (pssttyadd(pss, name, st.st_rdev))
334 {
335 closedir(dir);
336 return;
337 }
338 }
339 if (!sub)
340 break;
341 closedir(dir);
342 dir = sub;
343 sub = 0;
344 base = name;
345 }
346 closedir(dir);
347 }
348
349 /*
350 * return dev given tty base name
351 */
352
353 Pss_dev_t
pssttydev(register Pss_t * pss,const char * name)354 pssttydev(register Pss_t* pss, const char* name)
355 {
356 register const char* s;
357 register Tty_t* tty;
358 struct stat st;
359
360 s = name;
361 if (*s == '?' || *s == '-')
362 return PSS_NODEV;
363 if (pss->meth->ttydevf)
364 return (*pss->meth->ttydevf)(pss, s);
365 if (tty = (Tty_t*)dtmatch(pss->ttybyname, s))
366 return tty->dev;
367 if (stat(s, &st))
368 {
369 sfsprintf(pss->buf, sizeof(pss->buf), "/dev/%s", name);
370 s = (const char*)pss->buf;
371 if (stat(s, &st))
372 {
373 sfsprintf(pss->buf, sizeof(pss->buf), "/dev/tty%s", name);
374 if (stat(s, &st))
375 {
376 if (pss->disc->errorf)
377 (*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "%s: unknown tty", name);
378 }
379 }
380 }
381 pssttyadd(pss, name, st.st_rdev);
382 return st.st_rdev;
383 }
384
385 /*
386 * return tty base name given tty dev
387 */
388
389 char*
pssttyname(register Pss_t * pss,Pssent_t * pe)390 pssttyname(register Pss_t* pss, Pssent_t* pe)
391 {
392 register Tty_t* tty;
393 Pss_dev_t dev;
394 char* s;
395
396 if (pss->meth->ttynamef && (s = (*pss->meth->ttynamef)(pss, pe)))
397 return s;
398 if (pe->ttyname)
399 return pe->ttyname;
400 dev = pe->tty;
401 if (dev == PSS_NODEV)
402 return "?";
403 if (tty = (Tty_t*)dtmatch(pss->ttybydev, &dev))
404 return tty->name;
405 if (!pss->ttyscan)
406 ttyscan(pss);
407 if (tty = (Tty_t*)dtmatch(pss->ttybydev, &dev))
408 return tty->name;
409 sfsprintf(pss->buf, sizeof(pss->buf), "%03d,%03d", major(dev), minor(dev));
410 return pss->buf;
411 }
412