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