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_kvm implementation
26  */
27 
28 #include "psslib.h"
29 
30 #if PSS_METHOD != PSS_METHOD_kvm
31 
32 NoN(pss_kvm)
33 
34 #else
35 
36 #include <kvm.h>
37 #if _sys_time
38 #include <sys/time.h>
39 #endif
40 #if _sys_param
41 #include <sys/param.h>
42 #endif
43 #if _sys_proc
44 #include <sys/proc.h>
45 #endif
46 #if _sys_user
47 #include <sys/user.h>
48 #endif
49 #include <sys/sysctl.h>
50 #include <sys/tty.h>
51 
52 #if !_mem_p_pid_extern_proc
53 #define extern_proc		proc
54 #endif
55 
56 #ifndef SIDL
57 #ifdef	LSIDL
58 #define SIDL	LSIDL
59 #else
60 #define SIDL	1
61 #endif
62 #endif
63 #ifndef SRUN
64 #ifdef	LSRUN
65 #define SRUN	LSRUN
66 #else
67 #define SRUN	2
68 #endif
69 #endif
70 #ifndef SSLEEP
71 #ifdef	LSSLEEP
72 #define SSLEEP	LSSLEEP
73 #else
74 #define SSLEEP	3
75 #endif
76 #endif
77 #ifndef SSTOP
78 #ifdef	LSSTOP
79 #define SSTOP	LSSTOP
80 #else
81 #define SSTOP	4
82 #endif
83 #endif
84 #ifndef SZOMB
85 #ifdef	LSZOMB
86 #define SZOMB	LSZOMB
87 #else
88 #define SZOMB	5
89 #endif
90 #endif
91 #ifndef SDEAD
92 #ifdef	LSDEAD
93 #define SDEAD	LSDEAD
94 #else
95 #define SDEAD	6
96 #endif
97 #endif
98 #ifndef SONPROC
99 #ifdef	LSONPROC
100 #define SONPROC	LSONPROC
101 #else
102 #define SONPROC	7
103 #endif
104 #endif
105 #ifndef SSUSPENDED
106 #ifdef	LSSUSPENDED
107 #define SSUSPENDED	LSSUSPENDED
108 #else
109 #define SSUSPENDED	8
110 #endif
111 #endif
112 
113 typedef struct State_s
114 {
115 	kvm_t*			kd;
116 	struct kinfo_proc*	kp;
117 	struct kinfo_proc*	ke;
118 	struct extern_proc*	pr;
119 	struct eproc*		px;
120 } State_t;
121 
122 static int
123 kvm_init(Pss_t* pss)
124 {
125 	register State_t*	state;
126 
127 	if (!(state = vmnewof(pss->vm, 0, State_t, 1, 0)))
128 	{
129 		if (pss->disc->errorf)
130 			(*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|2, "out of space");
131 		return -1;
132 	}
133 	if (!(state->kd = kvm_open(NiL, NiL, 0, O_RDONLY, NiL)))
134 	{
135 		if (pss->disc->errorf)
136 			(*pss->disc->errorf)(pss, pss->disc, ERROR_SYSTEM|1, "kvm open error");
137 		return -1;
138 	}
139 	pss->data = state;
140 	error(1, "%s: pss method is currently incomplete", pss->meth->name);
141 	return 1;
142 }
143 
144 static int
145 kvm_done(Pss_t* pss)
146 {
147 	register State_t*	state = (State_t*)pss->data;
148 
149 	kvm_close(state->kd);
150 	return 1;
151 }
152 
153 static int
154 kvm_readf(Pss_t* pss, Pss_id_t pid)
155 {
156 	register State_t*	state = (State_t*)pss->data;
157 	int			count;
158 
159 	if (pid)
160 	{
161 		if (!(state->kp = kvm_getprocs(state->kd, KERN_PROC_PID, pid, &count)))
162 			return -1;
163 		state->ke = state->kp + count;
164 	}
165 	else if (!state->kp)
166 	{
167 		if (!(state->kp = kvm_getprocs(state->kd, KERN_PROC_ALL, 0, &count)))
168 			return -1;
169 		state->ke = state->kp + count;
170 	}
171 	if (state->kp >= state->ke)
172 		return 0;
173 	pss->pid = state->kp->kp_proc.p_pid;
174 	state->pr = &state->kp->kp_proc;
175 	state->px = &state->kp->kp_eproc;
176 	state->kp++;
177 	return 1;
178 }
179 
180 static int
181 kvm_part(register Pss_t* pss, register Pssent_t* pe)
182 {
183 	register State_t*	state = (State_t*)pss->data;
184 
185 	pe->pid = state->pr->p_pid;
186 	pe->pgrp = state->px->e_pgid;
187 	pe->tty = state->px->e_tdev;
188 	pe->uid = state->px->e_ucred.cr_uid;
189 #if 0
190 	pe->sid = state->px->e_sess->s_sid;
191 #endif
192 	switch (state->pr->p_stat)
193 	{
194 	case SIDL:	pe->state = 'I'; break;
195 	case SRUN:	pe->state = 'R'; break;
196 	case SSLEEP:	pe->state = 'S'; break;
197 	case SSTOP:	pe->state = 'T'; break;
198 	case SZOMB:	pe->state = 'Z'; break;
199 	default:	pe->state = 'O'; break;
200 	}
201 	return 1;
202 }
203 
204 static int
205 kvm_full(register Pss_t* pss, register Pssent_t* pe)
206 {
207 	register State_t*		state = (State_t*)pss->data;
208 	unsigned long			fields = pss->disc->fields & pss->meth->fields;
209 	char*				s;
210 	int				i;
211 
212 	if (pe->state != PSS_ZOMBIE)
213 	{
214 		if (fields & PSS_args)
215 		{
216 			s = state->pr->p_comm;
217 			if (s[0] == '(' && s[i = strlen(s) - 1] == ')')
218 			{
219 				s[i] = 0;
220 				s++;
221 			}
222 			pe->args = s;
223 		}
224 		if (fields & PSS_command)
225 		{
226 			s = state->pr->p_comm;
227 			if (s[0] == '(' && s[i = strlen(s) - 1] == ')')
228 			{
229 				s[i] = 0;
230 				s++;
231 			}
232 			pe->command = s;
233 		}
234 	}
235 #if _mem_p_addr_extern_proc
236 	pe->addr = state->pr->p_addr;
237 #endif
238 #if _mem_p_wchan_extern_proc
239 	pe->wchan = state->pr->p_wchan;
240 #endif
241 	pe->flags = state->pr->p_flag;
242 	pe->nice = state->pr->p_nice;
243 	pe->ppid = state->px->e_ppid;
244 #if PSS_pri && _mem_p_usrpri_extern_proc
245 	pe->pri = state->pr->p_usrpri;
246 #endif
247 #ifdef FWIDTH
248 	pe->cpu = state->pr->p_pctcpu >> FWIDTH;
249 #endif
250 	pe->refcount = state->px->e_xccount;
251 	pe->rss = state->px->e_xrssize;
252 #if _mem_e_xsize_eproc
253 	pe->size = state->px->e_xsize;
254 #else
255 	pe->size = state->px->e_vm.vm_tsize + state->px->e_vm.vm_dsize + state->px->e_vm.vm_ssize;
256 #endif
257 #if _mem_p_starttime_extern_proc
258 	pe->start = state->pr->p_starttime.tv_sec;
259 #endif
260 	pe->time = state->pr->p_rtime.tv_sec;
261 	return 1;
262 }
263 
264 static Pssmeth_t kvm_method =
265 {
266 	"kvm",
267 	"[-version?@(#)$Id: pss kvm (AT&T Research) 2008-01-31 $\n]"
268 	"[-author?Glenn Fowler <gsf@research.att.com>]",
269 	PSS_all,
270 	kvm_init,
271 	kvm_readf,
272 	kvm_part,
273 	kvm_full,
274 	0,
275 	0,
276 	0,
277 	kvm_done
278 };
279 
280 Pssmeth_t*	_pss_method = &kvm_method;
281 
282 #endif
283