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 <glenn.s.fowler@gmail.com>                *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22  * Glenn Fowler
23  * AT&T Research
24  *
25  * process status stream PSS_METHOD_ps implementation
26  */
27 
28 #include "psslib.h"
29 
30 #if !defined(PSS_ps) || !defined(PSS_pso)
31 
32 Pssmeth_t*	_pss_ps = 0;
33 
34 #else
35 
36 #include <tm.h>
37 
38 #define PSS_default	(PSS_pgrp|PSS_pid|PSS_ppid|PSS_sid|PSS_state|PSS_tgrp|PSS_tty|PSS_uid)
39 
40 typedef struct State_s
41 {
42 	Sfio_t*			ps;
43 	unsigned long		fields;
44 	unsigned long		now;
45 	int			scan;
46 	int			debug;
47 } State_t;
48 
49 typedef struct Pso_s
50 {
51 	unsigned long		field;
52 	const char*		name;
53 } Pso_t;
54 
55 static Pso_t	pso[] =
56 {
57 	PSS_pso
58 };
59 
60 static int
ps_init(Pss_t * pss)61 ps_init(Pss_t* pss)
62 {
63 	register State_t*	state;
64 	register Pso_t*		po;
65 	register unsigned long	fields;
66 	char*			s;
67 
68 	if (!(state = vmnewof(pss->vm, 0, State_t, 1, 0)))
69 	{
70 		if (pss->disc->errorf)
71 			(*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "out of space");
72 		return -1;
73 	}
74 	state->now = (unsigned long)time(NiL) + 60;
75 	if ((s = getenv("_AST_PSS_ps")) && *s == 'd')
76 		state->debug = 1;
77 	fields = 0;
78 	for (po = pso; po->field; po++)
79 		fields |= po->field;
80 	pss->meth->fields = state->fields = fields;
81 	pss->data = state;
82 	return 1;
83 }
84 
85 static int
ps_done(Pss_t * pss)86 ps_done(Pss_t* pss)
87 {
88 	register State_t*	state = (State_t*)pss->data;
89 
90 	if (state->ps)
91 		sfclose(state->ps);
92 	return 1;
93 }
94 
95 static int
ps_read(Pss_t * pss,Pss_id_t pid)96 ps_read(Pss_t* pss, Pss_id_t pid)
97 {
98 	register State_t*	state = (State_t*)pss->data;
99 	register Pso_t*		po;
100 	register char*		s;
101 	register char*		e;
102 	register unsigned long	fields;
103 	int			sep;
104 
105 	if (pid || !state->scan)
106 	{
107 		if (state->ps)
108 		{
109 			sfclose(state->ps);
110 			state->ps = 0;
111 		}
112 		s = pss->buf;
113 		e = s + sizeof(pss->buf);
114 		s += sfsprintf(s, e - s, "%s", PSS_ps);
115 		if (!pid)
116 		{
117 			if (pss->disc->flags & (PSS_ALL|PSS_UNMATCHED))
118 				s += sfsprintf(s, e - s, " %s", PSS_ps_every);
119 			else
120 				switch (pss->disc->flags & (PSS_ATTACHED|PSS_DETACHED|PSS_LEADER))
121 				{
122 				case PSS_ATTACHED|PSS_DETACHED|PSS_LEADER:
123 					s += sfsprintf(s, e - s, " %s", PSS_ps_every);
124 					break;
125 				case PSS_ATTACHED|PSS_DETACHED:
126 					s += sfsprintf(s, e - s, " %s", PSS_ps_detached);
127 					break;
128 				case PSS_DETACHED|PSS_LEADER:
129 					s += sfsprintf(s, e - s, " %s", PSS_ps_noleader);
130 					break;
131 				case PSS_ATTACHED|PSS_LEADER:
132 				case PSS_ATTACHED:
133 					s += sfsprintf(s, e - s, " %s", PSS_ps_all);
134 					break;
135 				}
136 		}
137 		s += sfsprintf(s, e - s, " -o");
138 		fields = pss->disc->fields|PSS_default;
139 		sep = ' ';
140 		for (po = pso; po->field; po++)
141 			if (po->field & fields)
142 			{
143 				s += sfsprintf(s, e - s, "%c%s", sep, po->name);
144 				sep = ',';
145 			}
146 		if (pid)
147 		{
148 			state->scan = 0;
149 			s += sfsprintf(s, e - s, " -p %lu", (unsigned long)pid);
150 		}
151 		else
152 			state->scan = 1;
153 		if ((pss->disc->flags & PSS_VERBOSE) && pss->disc->errorf)
154 			(*pss->disc->errorf)(pss, pss->disc, 0, "%s", pss->buf);
155 		if (!(state->ps = sfpopen(NiL, pss->buf, "r")) || !sfgetr(state->ps, '\n', 0))
156 			return -1;
157 	}
158 	return 1;
159 }
160 
161 static unsigned long
number(char * s,char ** p,int base)162 number(char* s, char** p, int base)
163 {
164 	unsigned long	n;
165 	char*		e;
166 
167 	for (;;)
168 	{
169 		n = strtoul(s, &e, base);
170 		if (*e && !isspace(*e))
171 			switch (base)
172 			{
173 			case 8:
174 				if (*e == '8' || *e == '9')
175 				{
176 					base = 10;
177 					continue;
178 				}
179 				/*FALLTHROUGH*/
180 			case 10:
181 				if (isxdigit(*e))
182 				{
183 					base = 16;
184 					continue;
185 				}
186 				break;
187 			}
188 		break;
189 	}
190 	while (*e && !isspace(*e))
191 		e++;
192 	*p = e;
193 	return n;
194 }
195 
196 static int
ps_part(register Pss_t * pss,register Pssent_t * pe)197 ps_part(register Pss_t* pss, register Pssent_t* pe)
198 {
199 	State_t*		state = (State_t*)pss->data;
200 	register Pso_t*		po;
201 	register unsigned long	fields;
202 	register char*		s;
203 	char*			e;
204 	char*			t;
205 	int			c;
206 
207 	if (!(s = sfgetr(state->ps, '\n', 1)))
208 		return -1;
209 	memset(pe, sizeof(*pe), 0);
210 	fields = pss->disc->fields|PSS_default;
211 	for (po = pso; po->field; po++)
212 		if (po->field & fields)
213 		{
214 			while (isspace(*s))
215 				s++;
216 			if (!*s)
217 				break;
218 			if (state->debug && pss->disc->errorf)
219 				(*pss->disc->errorf)(pss, pss->disc, 2, "%s: %s", po->name, s);
220 			switch (po->field)
221 			{
222 			case PSS_addr:
223 				pe->addr = (void*)number(s, &e, 16);
224 				break;
225 			case PSS_args:
226 				pe->args = e = s;
227 				return 1;
228 			case PSS_sched:
229 				pe->sched = e = s;
230 				break;
231 			case PSS_command:
232 				pe->command = (e = strrchr(s, '/')) ? (e + 1) : s;
233 				e = s;
234 				break;
235 			case PSS_cpu:
236 				pe->cpu = number(s, &e, 10);
237 				break;
238 			case PSS_flags:
239 				pe->flags = number(s, &e, 8);
240 				break;
241 			case PSS_gid:
242 				for (e = s; *e; e++)
243 					if (isspace(*e))
244 					{
245 						*e++ = 0;
246 						break;
247 					}
248 				pe->gid = strgid(s);
249 				break;
250 			case PSS_job:
251 				pe->job = number(s, &e, 10);
252 				break;
253 			case PSS_nice:
254 				pe->nice = number(s, &e, 10);
255 				break;
256 			case PSS_npid:
257 				pe->npid = number(s, &e, 10);
258 				break;
259 			case PSS_pgrp:
260 				pe->pgrp = number(s, &e, 10);
261 				break;
262 			case PSS_pid:
263 				pe->pid = number(s, &e, 10);
264 				break;
265 			case PSS_ppid:
266 				pe->ppid = number(s, &e, 10);
267 				break;
268 			case PSS_pri:
269 				pe->pri = number(s, &e, 10);
270 				break;
271 			case PSS_proc:
272 				pe->proc = number(s, &e, 10);
273 				break;
274 			case PSS_refcount:
275 				pe->refcount = number(s, &e, 10);
276 				break;
277 			case PSS_rss:
278 				pe->rss = number(s, &e, 10);
279 				break;
280 			case PSS_sid:
281 				pe->sid = number(s, &e, 10);
282 				break;
283 			case PSS_size:
284 				pe->size = number(s, &e, 10);
285 				break;
286 			case PSS_start:
287 				c = 0;
288 				for (t = s; *s; s++)
289 					if (*s == '_' || isalpha(*s) && isdigit(*(s + 1)) || isdigit(*s) && isalpha(*(s + 1)))
290 						c = 1;
291 					else if (isspace(*s) && (c || !isdigit(*(s + 1))))
292 						break;
293 				c = *s;
294 				*s = 0;
295 				pe->start = tmdate(t, &e, NiL);
296 				if ((unsigned long)pe->start > state->now)
297 				{
298 					sfsprintf(pss->buf, sizeof(pss->buf), "last %s", t);
299 					pe->start = tmdate(pss->buf, NiL, NiL);
300 				}
301 				*s = c;
302 				if (e > s)
303 					e = s;
304 				break;
305 			case PSS_state:
306 				if ((pe->state = *(e = s)) == PSS_ZOMBIE)
307 					*e = 0;
308 				break;
309 			case PSS_tgrp:
310 				pe->tgrp = number(s, &e, 10);
311 				break;
312 			case PSS_time:
313 				pe->time = strelapsed(s, &e, 1);
314 				break;
315 			case PSS_tty:
316 				for (e = s; *e; e++)
317 					if (isspace(*e))
318 					{
319 						*e++ = 0;
320 						break;
321 					}
322 				pe->tty = pssttydev(pss, s);
323 				break;
324 			case PSS_uid:
325 				for (e = s; *e; e++)
326 					if (isspace(*e))
327 					{
328 						*e++ = 0;
329 						break;
330 					}
331 				pe->uid = struid(s);
332 				break;
333 			case PSS_wchan:
334 				pe->wchan = (void*)number(s, &e, 16);
335 				break;
336 			}
337 			if (e == s)
338 				while (*s && !isspace(*s))
339 					s++;
340 			else
341 				s = e;
342 			if (isspace(*s))
343 				*s++ = 0;
344 		}
345 	return 1;
346 }
347 
348 static Pssmeth_t ps_method =
349 {
350 	"ps",
351 	"[-version?@(#)$Id: pss ps (AT&T Research) 2003-02-01 $\n]"
352 	"[-author?Glenn Fowler <gsf@research.att.com>]",
353 	PSS_all,
354 	ps_init,
355 	ps_read,
356 	ps_part,
357 	0,
358 	0,
359 	0,
360 	0,
361 	ps_done
362 };
363 
364 Pssmeth_t*	_pss_ps = &ps_method;
365 
366 #endif
367