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_procfs implementation
26  */
27 
28 #include "psslib.h"
29 
30 #if PSS_METHOD != PSS_METHOD_procfs
31 
32 NoN(pss_procfs)
33 
34 #else
35 
36 #if !defined(pr_clname) && !_mem_pr_clname_prpsinfo
37 #undef	PSS_sched
38 #define PSS_sched			0
39 #endif
40 
41 #if !defined(pr_gid) && !_mem_pr_gid_prpsinfo
42 #undef	PSS_gid
43 #define PSS_gid				0
44 #endif
45 
46 #if !defined(pr_lttydev) && !_mem_pr_lttydev_prpsinfo
47 #undef	_mem_pr_lttydev_prpsinfo
48 #define _mem_pr_lttydev_prpsinfo	0
49 #endif
50 
51 #if !_mem_pr_npid_prpsinfo
52 #if !defined(pr_ntpid) && !_mem_pr_ntpid_prpsinfo
53 #undef	PSS_npid
54 #define PSS_npid			0
55 #else
56 #define pr_npid				pr_ntpid
57 #endif
58 #endif
59 
60 #if !defined(pr_pgrp) && !_mem_pr_pgrp_prpsinfo
61 #if _mem_pr_pgid_prpsinfo
62 #undef	_mem_pr_pgrp_prpsinfo
63 #define _mem_pr_pgrp_prpsinfo		1
64 #define pr_pgrp				pr_pgid
65 #else
66 #undef	PSS_pgrp
67 #define PSS_pgrp			0
68 #endif
69 #endif
70 
71 #if !defined(pr_psargs) && !_mem_pr_psargs_prpsinfo
72 #undef	_mem_pr_psargs_prpsinfo
73 #define _mem_pr_psargs_prpsinfo		0
74 #endif
75 
76 #if !defined(pr_refcount) && !_mem_pr_refcount_prpsinfo
77 #undef	PSS_refcount
78 #define PSS_refcount			0
79 #endif
80 
81 #if !defined(pr_rssize) && !_mem_pr_rssize_prpsinfo
82 #undef	PSS_rss
83 #define PSS_rss				0
84 #endif
85 
86 #if !defined(pr_sonproc) && !_mem_pr_sonproc_prpsinfo
87 #undef	PSS_proc
88 #define PSS_proc			0
89 #endif
90 
91 #if !defined(pr_sid) && !_mem_pr_sid_prpsinfo
92 #undef	PSS_sid
93 #define PSS_sid				0
94 #define pr_sid				pr_tgrp
95 #endif
96 
97 #if !defined(pr_tgrp) && !_mem_pr_tgrp_prpsinfo
98 #undef	PSS_tgrp
99 #define PSS_tgrp			0
100 #define pr_tgrp				pr_pgrp
101 #endif
102 
103 typedef struct State_s
104 {
105 	struct prpsinfo		pr;
106 	DIR*			dir;
107 } State_t;
108 
109 static int
110 procfs_init(Pss_t* pss)
111 {
112 	register State_t*	state;
113 	int			fd;
114 
115 	sfsprintf(pss->buf, sizeof(pss->buf), _PS_path_num, (unsigned long)1, _PS_status);
116 	if ((fd = open(pss->buf, O_RDONLY|O_BINARY)) < 0)
117 		return -1;
118 	close(fd);
119 	if (!(state = vmnewof(pss->vm, 0, State_t, 1, 0)))
120 	{
121 		if (pss->disc->errorf)
122 			(*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "out of space");
123 		return -1;
124 	}
125 	if (!(state->dir = opendir(_PS_dir)))
126 	{
127 		if (pss->disc->errorf)
128 			(*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|1, "%s: cannot open", _PS_dir);
129 		return -1;
130 	}
131 	pss->data = state;
132 	return 1;
133 }
134 
135 static int
136 procfs_done(Pss_t* pss)
137 {
138 	register State_t*	state = (State_t*)pss->data;
139 
140 	closedir(state->dir);
141 	return 1;
142 }
143 
144 static int
145 procfs_read(Pss_t* pss, Pss_id_t pid)
146 {
147 	register State_t*	state = (State_t*)pss->data;
148 	struct dirent*		ent;
149 	char*			e;
150 
151 	if (pid)
152 		pss->pid = pid;
153 	else
154 		do
155 		{
156 			if (!(ent = readdir(state->dir)))
157 				return 0;
158 			pss->pid = (Pss_id_t)strtol(ent->d_name, &e, 10);
159 		} while (*e);
160 	return 1;
161 }
162 
163 static int
164 procfs_part(register Pss_t* pss, register Pssent_t* pe)
165 {
166 	register State_t*		state = (State_t*)pss->data;
167 	register struct prpsinfo*	pr = &state->pr;
168 	register int			fd;
169 	int				n;
170 #if defined(_PS_scan_binary) || defined(_PS_scan_format)
171 	struct stat			st;
172 #endif
173 
174 	sfsprintf(pss->buf, sizeof(pss->buf), _PS_path_num, (unsigned long)pss->pid, _PS_status);
175 	if ((fd = open(pss->buf, O_RDONLY|O_BINARY)) < 0)
176 	{
177 		if (pss->disc->errorf && ((pss->disc->flags & PSS_VERBOSE) || errno != ENOENT))
178 			(*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "%lu: cannot stat process", pss->pid);
179 		return 0;
180 	}
181 #ifdef _PS_scan_format
182 	if ((n = read(fd, pss->buf, sizeof(pss->buf))) <= 0 || fstat(fd, &st))
183 	{
184 		n = -1;
185 		errno = EINVAL;
186 	}
187 	else
188 	{
189 		memset(pr, sizeof(*pr), 0);
190 		n = sfsscanf(pss->buf, _PS_scan_format, _PS_scan_args(pr));
191 		if (n < _PS_scan_count)
192 		{
193 			register char*	s;
194 
195 			for (s = pss->buf; *s; s++)
196 				if (*s == '(')
197 				{
198 					for (; *s && *s != ')'; s++)
199 						if (isspace(*s))
200 							*s = '_';
201 					break;
202 				}
203 			n = sfsscanf(pss->buf, _PS_scan_format, _PS_scan_args(pr));
204 			if (n < _PS_scan_count)
205 				error(1, "%lu: scan count %d, expected at least %d", (unsigned long)pss->pid, n, _PS_scan_count);
206 		}
207 #ifdef _PS_scan_fix
208 		_PS_scan_fix(pr, pe);
209 #endif
210 #ifdef _PS_task
211 		sfsprintf(pss->buf, sizeof(pss->buf), _PS_path_num, (unsigned long)pss->pid, _PS_task);
212 		(void)stat(pss->buf, &st);
213 #endif
214 		pr->pr_uid = st.st_uid;
215 		pr->pr_gid = st.st_gid;
216 		pr->pr_nice = pr->pr_priority - 15;
217 		pr->pr_size /= 1024;
218 #if _mem_pr_rssize_prpsinfo
219 		pr->pr_rssize /= 1024;
220 #endif
221 #ifdef _PS_scan_boot
222 		if (!pss->boot)
223 		{
224 			register char*	s;
225 			Sfio_t*		fp;
226 
227 			pss->boot = 1;
228 			if (fp = sfopen(NiL, "/proc/stat", "r"))
229 			{
230 				while (s = sfgetr(fp, '\n', 0))
231 					if (strneq(s, "btime ", 6))
232 					{
233 						pss->boot = strtol(s + 6, NiL, 10);
234 						break;
235 					}
236 				sfclose(fp);
237 			}
238 			if (!(pss->hz = (int)strtol(astconf("CLK_TCK", NiL, NiL), NiL, 0)))
239 				pss->hz = PR_HZ;
240 		}
241 		pr->pr_start = pss->boot + pr->pr_start / pss->hz;
242 #endif
243 	}
244 #else
245 #ifdef _PS_scan_binary
246 	n = read(fd, pr, sizeof(*pr)) == sizeof(*pr) ? 1 : -1;
247 #else
248 	n = ioctl(fd, PIOCPSINFO, pr);
249 #endif
250 #endif
251 	close(fd);
252 	if (n < 0)
253 	{
254 		if (pss->disc->errorf)
255 			(*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "%lu: cannot get process info", pss->pid);
256 		return 0;
257 	}
258 #if _UTS
259 	if (pr->pr_pri > 99)
260 		pr->pr_pri = 99;
261 	else if (pr->pr_pri < 0)
262 		pr->pr_pri = 0;
263 	pr->pr_ttydev = makedev((pr->pr_ttydev >> 18) & ((1<<14)-1), pr->pr_ttydev & ((1<<18)-1));
264 #endif
265 #if PSS_gid
266 	pe->gid = pr->pr_gid;
267 #endif
268 #if PSS_pgrp
269 	pe->pgrp = pr->pr_pgrp;
270 #endif
271 	pe->pid = pr->pr_pid;
272 #if PSS_sid
273 	pe->sid = pr->pr_sid;
274 #endif
275 	pe->state = PR_ZOMBIE(pr) ? PSS_ZOMBIE : pr->pr_sname;
276 #if PSS_tgrp
277 	pe->tgrp = pr->pr_tgrp;
278 #endif
279 	pe->tty = (pr->pr_ttydev == (Pss_dev_t)PRNODEV) ? PSS_NODEV : pr->pr_ttydev;
280 	pe->uid = pr->pr_uid;
281 	return 1;
282 }
283 
284 static int
285 procfs_full(register Pss_t* pss, register Pssent_t* pe)
286 {
287 	register State_t*		state = (State_t*)pss->data;
288 	register struct prpsinfo*	pr = &state->pr;
289 	unsigned long			fields = pss->disc->fields & pss->meth->fields;
290 	char*				s;
291 	int				i;
292 
293 	if (pe->state != PSS_ZOMBIE)
294 	{
295 		if (fields & PSS_args)
296 		{
297 #if _mem_pr_psargs_prpsinfo
298 			s = pr->pr_psargs;
299 #else
300 #ifdef _PS_args
301 			s = "<unknown>";
302 			sfsprintf(pss->buf, sizeof(pss->buf), _PS_path_num, pe->pid, _PS_args);
303 			if ((i = open(pss->buf, O_RDONLY|O_BINARY)) >= 0)
304 			{
305 				int	n;
306 
307 				n = read(i, pss->buf, sizeof(pss->buf) - 1);
308 				close(i);
309 				if (n > 0)
310 				{
311 					s = pss->buf;
312 					for (i = 0; i < n; i++)
313 						if (!s[i])
314 							s[i] = ' ';
315 					s[i] = 0;
316 				}
317 			}
318 #else
319 			s = pr->pr_fname;
320 			if (s[0] == '(' && s[i = strlen(s) - 1] == ')')
321 			{
322 				s[i] = 0;
323 				s++;
324 			}
325 #endif
326 #endif
327 			pe->args = s;
328 		}
329 		if (fields & PSS_command)
330 		{
331 			s = pr->pr_fname;
332 			if (s[0] == '(' && s[i = strlen(s) - 1] == ')')
333 			{
334 				s[i] = 0;
335 				s++;
336 			}
337 			pe->command = s;
338 		}
339 	}
340 	pe->addr = (void*)pr->pr_addr;
341 #if _mem_pr_clname_prpsinfo
342 	pe->sched = pr->pr_clname;
343 #endif
344 	pe->cpu = PR_CPU(pr);
345 	pe->flags = pr->pr_flag;
346 	pe->nice = pr->pr_nice;
347 #if _mem_pr_npid_prpsinfo
348 	pe->npid = pr->pr_npid;
349 #else
350 #if _mem_pr_ntpid_prpsinfo
351 	pe->npid = pr->pr_ntpid;
352 #endif
353 #endif
354 	pe->ppid = pr->pr_ppid;
355 	pe->pri = pr->pr_pri;
356 #if _mem_pr_sonproc_prpsinfo
357 	pe->proc = pr->pr_sonproc;
358 #endif
359 #if _mem_pr_refcount_prpsinfo
360 	pe->refcount = pr->pr_refcount;
361 #endif
362 #if _mem_pr_rssize_prpsinfo
363 	pe->rss = pr->pr_rssize;
364 #endif
365 	pe->size = pr->pr_size;
366 	pe->start = PR_START(pr);
367 	pe->time = PR_TIME(pr);
368 	pe->wchan = (void*)pr->pr_wchan;
369 	return 1;
370 }
371 
372 static Pssmeth_t procfs_method =
373 {
374 	"/proc",
375 	"[-version?@(#)$Id: pss /proc (AT&T Research) 2011-12-13 $\n]"
376 	"[-author?Glenn Fowler <gsf@research.att.com>]",
377 	PSS_all,
378 	procfs_init,
379 	procfs_read,
380 	procfs_part,
381 	procfs_full,
382 	0,
383 	0,
384 	0,
385 	procfs_done
386 };
387 
388 Pssmeth_t*	_pss_method = &procfs_method;
389 
390 #endif
391