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