1 |
|
|
/* $OpenBSD: kvm_proc2.c,v 1.27 2016/11/07 00:26:33 guenther Exp $ */ |
2 |
|
|
/* $NetBSD: kvm_proc.c,v 1.30 1999/03/24 05:50:50 mrg Exp $ */ |
3 |
|
|
/*- |
4 |
|
|
* Copyright (c) 1998 The NetBSD Foundation, Inc. |
5 |
|
|
* All rights reserved. |
6 |
|
|
* |
7 |
|
|
* This code is derived from software contributed to The NetBSD Foundation |
8 |
|
|
* by Charles M. Hannum. |
9 |
|
|
* |
10 |
|
|
* Redistribution and use in source and binary forms, with or without |
11 |
|
|
* modification, are permitted provided that the following conditions |
12 |
|
|
* are met: |
13 |
|
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
16 |
|
|
* notice, this list of conditions and the following disclaimer in the |
17 |
|
|
* documentation and/or other materials provided with the distribution. |
18 |
|
|
* |
19 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 |
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 |
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 |
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 |
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 |
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 |
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 |
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 |
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 |
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 |
|
|
* POSSIBILITY OF SUCH DAMAGE. |
30 |
|
|
*/ |
31 |
|
|
/*- |
32 |
|
|
* Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. |
33 |
|
|
* Copyright (c) 1989, 1992, 1993 |
34 |
|
|
* The Regents of the University of California. All rights reserved. |
35 |
|
|
* |
36 |
|
|
* This code is derived from software developed by the Computer Systems |
37 |
|
|
* Engineering group at Lawrence Berkeley Laboratory under DARPA contract |
38 |
|
|
* BG 91-66 and contributed to Berkeley. |
39 |
|
|
* |
40 |
|
|
* Redistribution and use in source and binary forms, with or without |
41 |
|
|
* modification, are permitted provided that the following conditions |
42 |
|
|
* are met: |
43 |
|
|
* 1. Redistributions of source code must retain the above copyright |
44 |
|
|
* notice, this list of conditions and the following disclaimer. |
45 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
46 |
|
|
* notice, this list of conditions and the following disclaimer in the |
47 |
|
|
* documentation and/or other materials provided with the distribution. |
48 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
49 |
|
|
* may be used to endorse or promote products derived from this software |
50 |
|
|
* without specific prior written permission. |
51 |
|
|
* |
52 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
53 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
54 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
55 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
56 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
57 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
58 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
59 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
60 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
61 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
62 |
|
|
* SUCH DAMAGE. |
63 |
|
|
*/ |
64 |
|
|
|
65 |
|
|
/* |
66 |
|
|
* Proc traversal interface for kvm. ps and w are (probably) the exclusive |
67 |
|
|
* users of this code, so we've factored it out into a separate module. |
68 |
|
|
* Thus, we keep this grunge out of the other kvm applications (i.e., |
69 |
|
|
* most other applications are interested only in open/close/read/nlist). |
70 |
|
|
*/ |
71 |
|
|
|
72 |
|
|
#define __need_process |
73 |
|
|
#include <sys/param.h> |
74 |
|
|
#include <sys/proc.h> |
75 |
|
|
#include <sys/exec.h> |
76 |
|
|
#include <sys/stat.h> |
77 |
|
|
#include <sys/ucred.h> |
78 |
|
|
#include <sys/ioctl.h> |
79 |
|
|
#include <sys/tty.h> |
80 |
|
|
#include <sys/resource.h> |
81 |
|
|
#include <sys/resourcevar.h> |
82 |
|
|
#include <sys/signalvar.h> |
83 |
|
|
#include <stddef.h> |
84 |
|
|
#include <stdlib.h> |
85 |
|
|
#include <string.h> |
86 |
|
|
#include <unistd.h> |
87 |
|
|
#include <nlist.h> |
88 |
|
|
#include <kvm.h> |
89 |
|
|
|
90 |
|
|
#include <uvm/uvm_extern.h> |
91 |
|
|
#include <uvm/uvm_amap.h> |
92 |
|
|
#include <machine/vmparam.h> |
93 |
|
|
#include <machine/pmap.h> |
94 |
|
|
|
95 |
|
|
#include <sys/sysctl.h> |
96 |
|
|
|
97 |
|
|
#include <limits.h> |
98 |
|
|
#include <errno.h> |
99 |
|
|
#include <db.h> |
100 |
|
|
#include <paths.h> |
101 |
|
|
|
102 |
|
|
#include "kvm_private.h" |
103 |
|
|
|
104 |
|
|
/* |
105 |
|
|
* Read proc's from memory file into buffer bp, which has space to hold |
106 |
|
|
* at most maxcnt procs. |
107 |
|
|
*/ |
108 |
|
|
static int |
109 |
|
|
kvm_proclist(kvm_t *kd, int op, int arg, struct process *pr, |
110 |
|
|
char *bp, int maxcnt, size_t esize) |
111 |
|
|
{ |
112 |
|
|
struct kinfo_proc kp; |
113 |
|
|
struct session sess; |
114 |
|
|
struct ucred ucred; |
115 |
|
|
struct proc proc, *p; |
116 |
|
|
struct process process, process2; |
117 |
|
|
struct pgrp pgrp; |
118 |
|
|
struct tty tty; |
119 |
|
|
struct sigacts sa, *sap; |
120 |
|
|
struct vmspace vm, *vmp; |
121 |
|
|
struct plimit limits, *limp; |
122 |
|
|
pid_t parent_pid, leader_pid; |
123 |
|
|
int cnt = 0; |
124 |
|
|
int dothreads = 0; |
125 |
|
|
|
126 |
|
|
dothreads = op & KERN_PROC_SHOW_THREADS; |
127 |
|
|
op &= ~KERN_PROC_SHOW_THREADS; |
128 |
|
|
|
129 |
|
|
/* |
130 |
|
|
* Modelled on sysctl_doproc() in sys/kern/kern_sysctl.c |
131 |
|
|
*/ |
132 |
|
|
for (; cnt < maxcnt && pr != NULL; pr = LIST_NEXT(&process, ps_list)) { |
133 |
|
|
if (KREAD(kd, (u_long)pr, &process)) { |
134 |
|
|
_kvm_err(kd, kd->program, "can't read process at %lx", |
135 |
|
|
(u_long)pr); |
136 |
|
|
return (-1); |
137 |
|
|
} |
138 |
|
|
if (process.ps_pgrp == NULL) |
139 |
|
|
continue; |
140 |
|
|
if (process.ps_flags & PS_EMBRYO) |
141 |
|
|
continue; |
142 |
|
|
if (KREAD(kd, (u_long)process.ps_ucred, &ucred)) { |
143 |
|
|
_kvm_err(kd, kd->program, "can't read ucred at %lx", |
144 |
|
|
(u_long)process.ps_ucred); |
145 |
|
|
return (-1); |
146 |
|
|
} |
147 |
|
|
if (KREAD(kd, (u_long)process.ps_pgrp, &pgrp)) { |
148 |
|
|
_kvm_err(kd, kd->program, "can't read pgrp at %lx", |
149 |
|
|
(u_long)process.ps_pgrp); |
150 |
|
|
return (-1); |
151 |
|
|
} |
152 |
|
|
if (KREAD(kd, (u_long)pgrp.pg_session, &sess)) { |
153 |
|
|
_kvm_err(kd, kd->program, "can't read session at %lx", |
154 |
|
|
(u_long)pgrp.pg_session); |
155 |
|
|
return (-1); |
156 |
|
|
} |
157 |
|
|
if ((process.ps_flags & PS_CONTROLT) && sess.s_ttyp != NULL && |
158 |
|
|
KREAD(kd, (u_long)sess.s_ttyp, &tty)) { |
159 |
|
|
_kvm_err(kd, kd->program, "can't read tty at %lx", |
160 |
|
|
(u_long)sess.s_ttyp); |
161 |
|
|
return (-1); |
162 |
|
|
} |
163 |
|
|
if (process.ps_pptr) { |
164 |
|
|
if (KREAD(kd, (u_long)process.ps_pptr, &process2)) { |
165 |
|
|
_kvm_err(kd, kd->program, |
166 |
|
|
"can't read process at %lx", |
167 |
|
|
(u_long)process.ps_pptr); |
168 |
|
|
return (-1); |
169 |
|
|
} |
170 |
|
|
parent_pid = process2.ps_pid; |
171 |
|
|
} |
172 |
|
|
else |
173 |
|
|
parent_pid = 0; |
174 |
|
|
if (sess.s_leader) { |
175 |
|
|
if (KREAD(kd, (u_long)sess.s_leader, &process2)) { |
176 |
|
|
_kvm_err(kd, kd->program, |
177 |
|
|
"can't read proc at %lx", |
178 |
|
|
(u_long)sess.s_leader); |
179 |
|
|
return (-1); |
180 |
|
|
} |
181 |
|
|
leader_pid = process2.ps_pid; |
182 |
|
|
} |
183 |
|
|
else |
184 |
|
|
leader_pid = 0; |
185 |
|
|
if (process.ps_sigacts) { |
186 |
|
|
if (KREAD(kd, (u_long)process.ps_sigacts, &sa)) { |
187 |
|
|
_kvm_err(kd, kd->program, |
188 |
|
|
"can't read sigacts at %lx", |
189 |
|
|
(u_long)process.ps_sigacts); |
190 |
|
|
return (-1); |
191 |
|
|
} |
192 |
|
|
sap = &sa; |
193 |
|
|
} |
194 |
|
|
else |
195 |
|
|
sap = NULL; |
196 |
|
|
|
197 |
|
|
switch (op) { |
198 |
|
|
case KERN_PROC_PID: |
199 |
|
|
if (parent_pid != (pid_t)arg) |
200 |
|
|
continue; |
201 |
|
|
break; |
202 |
|
|
|
203 |
|
|
case KERN_PROC_PGRP: |
204 |
|
|
if (pgrp.pg_id != (pid_t)arg) |
205 |
|
|
continue; |
206 |
|
|
break; |
207 |
|
|
|
208 |
|
|
case KERN_PROC_SESSION: |
209 |
|
|
if (sess.s_leader == NULL || |
210 |
|
|
leader_pid != (pid_t)arg) |
211 |
|
|
continue; |
212 |
|
|
break; |
213 |
|
|
|
214 |
|
|
case KERN_PROC_TTY: |
215 |
|
|
if ((process.ps_flags & PS_CONTROLT) == 0 || |
216 |
|
|
sess.s_ttyp == NULL || |
217 |
|
|
tty.t_dev != (dev_t)arg) |
218 |
|
|
continue; |
219 |
|
|
break; |
220 |
|
|
|
221 |
|
|
case KERN_PROC_UID: |
222 |
|
|
if (ucred.cr_uid != (uid_t)arg) |
223 |
|
|
continue; |
224 |
|
|
break; |
225 |
|
|
|
226 |
|
|
case KERN_PROC_RUID: |
227 |
|
|
if (ucred.cr_ruid != (uid_t)arg) |
228 |
|
|
continue; |
229 |
|
|
break; |
230 |
|
|
|
231 |
|
|
case KERN_PROC_ALL: |
232 |
|
|
if (process.ps_flags & PS_SYSTEM) |
233 |
|
|
continue; |
234 |
|
|
break; |
235 |
|
|
|
236 |
|
|
case KERN_PROC_KTHREAD: |
237 |
|
|
/* no filtering */ |
238 |
|
|
break; |
239 |
|
|
|
240 |
|
|
default: |
241 |
|
|
_kvm_err(kd, kd->program, "invalid filter"); |
242 |
|
|
return (-1); |
243 |
|
|
} |
244 |
|
|
|
245 |
|
|
/* |
246 |
|
|
* We're going to add another proc to the set. If this |
247 |
|
|
* will overflow the buffer, assume the reason is because |
248 |
|
|
* nthreads (or the proc list) is corrupt and declare an error. |
249 |
|
|
*/ |
250 |
|
|
if (cnt >= maxcnt) { |
251 |
|
|
_kvm_err(kd, kd->program, "nthreads corrupt"); |
252 |
|
|
return (-1); |
253 |
|
|
} |
254 |
|
|
|
255 |
|
|
/* set up stuff that might not always be there */ |
256 |
|
|
limp = &limits; |
257 |
|
|
if (!process.ps_limit || |
258 |
|
|
KREAD(kd, (u_long)process.ps_limit, &limits)) |
259 |
|
|
limp = NULL; |
260 |
|
|
|
261 |
|
|
vmp = NULL; |
262 |
|
|
|
263 |
|
|
if ((process.ps_flags & PS_ZOMBIE) == 0 && |
264 |
|
|
!KREAD(kd, (u_long)process.ps_vmspace, &vm)) |
265 |
|
|
vmp = &vm; |
266 |
|
|
|
267 |
|
|
#define do_copy_str(_d, _s, _l) kvm_read(kd, (u_long)(_s), (_d), (_l)-1) |
268 |
|
|
FILL_KPROC(&kp, do_copy_str, &proc, &process, |
269 |
|
|
&ucred, &pgrp, process.ps_mainproc, pr, &sess, |
270 |
|
|
vmp, limp, sap, 0, 1); |
271 |
|
|
|
272 |
|
|
/* stuff that's too painful to generalize */ |
273 |
|
|
kp.p_ppid = parent_pid; |
274 |
|
|
kp.p_sid = leader_pid; |
275 |
|
|
if ((process.ps_flags & PS_CONTROLT) && sess.s_ttyp != NULL) { |
276 |
|
|
kp.p_tdev = tty.t_dev; |
277 |
|
|
if (tty.t_pgrp != NULL && |
278 |
|
|
tty.t_pgrp != process.ps_pgrp && |
279 |
|
|
KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) { |
280 |
|
|
_kvm_err(kd, kd->program, |
281 |
|
|
"can't read tpgrp at %lx", |
282 |
|
|
(u_long)tty.t_pgrp); |
283 |
|
|
return (-1); |
284 |
|
|
} |
285 |
|
|
kp.p_tpgid = tty.t_pgrp ? pgrp.pg_id : -1; |
286 |
|
|
kp.p_tsess = PTRTOINT64(tty.t_session); |
287 |
|
|
} else { |
288 |
|
|
kp.p_tpgid = -1; |
289 |
|
|
kp.p_tdev = NODEV; |
290 |
|
|
} |
291 |
|
|
|
292 |
|
|
/* update %cpu for all threads */ |
293 |
|
|
if (dothreads) { |
294 |
|
|
if (KREAD(kd, (u_long)process.ps_mainproc, &proc)) { |
295 |
|
|
_kvm_err(kd, kd->program, |
296 |
|
|
"can't read proc at %lx", |
297 |
|
|
(u_long)process.ps_mainproc); |
298 |
|
|
return (-1); |
299 |
|
|
} |
300 |
|
|
kp.p_pctcpu = proc.p_pctcpu; |
301 |
|
|
kp.p_stat = proc.p_stat; |
302 |
|
|
} else { |
303 |
|
|
kp.p_pctcpu = 0; |
304 |
|
|
kp.p_stat = (process.ps_flags & PS_ZOMBIE) ? SDEAD : |
305 |
|
|
SIDL; |
306 |
|
|
for (p = TAILQ_FIRST(&process.ps_threads); p != NULL; |
307 |
|
|
p = TAILQ_NEXT(&proc, p_thr_link)) { |
308 |
|
|
if (KREAD(kd, (u_long)p, &proc)) { |
309 |
|
|
_kvm_err(kd, kd->program, |
310 |
|
|
"can't read proc at %lx", |
311 |
|
|
(u_long)p); |
312 |
|
|
return (-1); |
313 |
|
|
} |
314 |
|
|
kp.p_pctcpu += proc.p_pctcpu; |
315 |
|
|
/* |
316 |
|
|
* find best state: |
317 |
|
|
* ONPROC > RUN > STOP > SLEEP > ... |
318 |
|
|
*/ |
319 |
|
|
if (proc.p_stat == SONPROC || |
320 |
|
|
kp.p_stat == SONPROC) |
321 |
|
|
kp.p_stat = SONPROC; |
322 |
|
|
else if (proc.p_stat == SRUN || |
323 |
|
|
kp.p_stat == SRUN) |
324 |
|
|
kp.p_stat = SRUN; |
325 |
|
|
else if (proc.p_stat == SSTOP || |
326 |
|
|
kp.p_stat == SSTOP) |
327 |
|
|
kp.p_stat = SSTOP; |
328 |
|
|
else if (proc.p_stat == SSLEEP) |
329 |
|
|
kp.p_stat = SSLEEP; |
330 |
|
|
} |
331 |
|
|
} |
332 |
|
|
|
333 |
|
|
memcpy(bp, &kp, esize); |
334 |
|
|
bp += esize; |
335 |
|
|
++cnt; |
336 |
|
|
|
337 |
|
|
/* Skip per-thread entries if not required by op */ |
338 |
|
|
if (!dothreads) |
339 |
|
|
continue; |
340 |
|
|
|
341 |
|
|
for (p = TAILQ_FIRST(&process.ps_threads); p != NULL; |
342 |
|
|
p = TAILQ_NEXT(&proc, p_thr_link)) { |
343 |
|
|
if (KREAD(kd, (u_long)p, &proc)) { |
344 |
|
|
_kvm_err(kd, kd->program, |
345 |
|
|
"can't read proc at %lx", |
346 |
|
|
(u_long)p); |
347 |
|
|
return (-1); |
348 |
|
|
} |
349 |
|
|
FILL_KPROC(&kp, do_copy_str, &proc, &process, |
350 |
|
|
&ucred, &pgrp, p, pr, &sess, vmp, limp, sap, |
351 |
|
|
1, 1); |
352 |
|
|
|
353 |
|
|
/* see above */ |
354 |
|
|
kp.p_ppid = parent_pid; |
355 |
|
|
kp.p_sid = leader_pid; |
356 |
|
|
if ((process.ps_flags & PS_CONTROLT) && |
357 |
|
|
sess.s_ttyp != NULL) { |
358 |
|
|
kp.p_tdev = tty.t_dev; |
359 |
|
|
if (tty.t_pgrp != NULL && |
360 |
|
|
tty.t_pgrp != process.ps_pgrp && |
361 |
|
|
KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) { |
362 |
|
|
_kvm_err(kd, kd->program, |
363 |
|
|
"can't read tpgrp at %lx", |
364 |
|
|
(u_long)tty.t_pgrp); |
365 |
|
|
return (-1); |
366 |
|
|
} |
367 |
|
|
kp.p_tpgid = tty.t_pgrp ? pgrp.pg_id : -1; |
368 |
|
|
kp.p_tsess = PTRTOINT64(tty.t_session); |
369 |
|
|
} else { |
370 |
|
|
kp.p_tpgid = -1; |
371 |
|
|
kp.p_tdev = NODEV; |
372 |
|
|
} |
373 |
|
|
} |
374 |
|
|
|
375 |
|
|
memcpy(bp, &kp, esize); |
376 |
|
|
bp += esize; |
377 |
|
|
++cnt; |
378 |
|
|
#undef do_copy_str |
379 |
|
|
} |
380 |
|
|
return (cnt); |
381 |
|
|
} |
382 |
|
|
|
383 |
|
|
struct kinfo_proc * |
384 |
|
|
kvm_getprocs(kvm_t *kd, int op, int arg, size_t esize, int *cnt) |
385 |
|
|
{ |
386 |
|
|
int mib[6], st, nthreads; |
387 |
|
|
void *procbase; |
388 |
|
|
size_t size; |
389 |
|
|
|
390 |
|
|
if ((ssize_t)esize < 0) |
391 |
|
|
return (NULL); |
392 |
|
|
|
393 |
|
|
if (ISALIVE(kd)) { |
394 |
|
|
size = 0; |
395 |
|
|
mib[0] = CTL_KERN; |
396 |
|
|
mib[1] = KERN_PROC; |
397 |
|
|
mib[2] = op; |
398 |
|
|
mib[3] = arg; |
399 |
|
|
mib[4] = esize; |
400 |
|
|
|
401 |
|
|
do { |
402 |
|
|
mib[5] = 0; |
403 |
|
|
st = sysctl(mib, 6, NULL, &size, NULL, 0); |
404 |
|
|
if (st == -1) { |
405 |
|
|
_kvm_syserr(kd, kd->program, "kvm_getprocs"); |
406 |
|
|
return (NULL); |
407 |
|
|
} |
408 |
|
|
|
409 |
|
|
size += size / 8; /* add ~10% */ |
410 |
|
|
|
411 |
|
|
procbase = _kvm_realloc(kd, kd->procbase, size); |
412 |
|
|
if (procbase == NULL) |
413 |
|
|
return (NULL); |
414 |
|
|
|
415 |
|
|
kd->procbase = procbase; |
416 |
|
|
|
417 |
|
|
mib[5] = size / esize; |
418 |
|
|
st = sysctl(mib, 6, kd->procbase, &size, NULL, 0); |
419 |
|
|
if (st == -1 && errno != ENOMEM) { |
420 |
|
|
_kvm_syserr(kd, kd->program, "kvm_getprocs"); |
421 |
|
|
return (NULL); |
422 |
|
|
} |
423 |
|
|
} while (st == -1); |
424 |
|
|
|
425 |
|
|
nthreads = size / esize; |
426 |
|
|
} else { |
427 |
|
|
struct nlist nl[5]; |
428 |
|
|
int i, maxthread, maxprocess; |
429 |
|
|
struct process *pr; |
430 |
|
|
char *bp; |
431 |
|
|
|
432 |
|
|
if (esize > sizeof(struct kinfo_proc)) { |
433 |
|
|
_kvm_syserr(kd, kd->program, |
434 |
|
|
"kvm_getprocs: unknown fields requested: libkvm out of date?"); |
435 |
|
|
return (NULL); |
436 |
|
|
} |
437 |
|
|
|
438 |
|
|
memset(nl, 0, sizeof(nl)); |
439 |
|
|
nl[0].n_name = "_nthreads"; |
440 |
|
|
nl[1].n_name = "_nprocesses"; |
441 |
|
|
nl[2].n_name = "_allprocess"; |
442 |
|
|
nl[3].n_name = "_zombprocess"; |
443 |
|
|
nl[4].n_name = NULL; |
444 |
|
|
|
445 |
|
|
if (kvm_nlist(kd, nl) != 0) { |
446 |
|
|
for (i = 0; nl[i].n_type != 0; ++i) |
447 |
|
|
; |
448 |
|
|
_kvm_err(kd, kd->program, |
449 |
|
|
"%s: no such symbol", nl[i].n_name); |
450 |
|
|
return (NULL); |
451 |
|
|
} |
452 |
|
|
if (KREAD(kd, nl[0].n_value, &maxthread)) { |
453 |
|
|
_kvm_err(kd, kd->program, "can't read nthreads"); |
454 |
|
|
return (NULL); |
455 |
|
|
} |
456 |
|
|
if (KREAD(kd, nl[1].n_value, &maxprocess)) { |
457 |
|
|
_kvm_err(kd, kd->program, "can't read nprocesses"); |
458 |
|
|
return (NULL); |
459 |
|
|
} |
460 |
|
|
maxthread += maxprocess; |
461 |
|
|
|
462 |
|
|
kd->procbase = _kvm_reallocarray(kd, NULL, maxthread, esize); |
463 |
|
|
if (kd->procbase == 0) |
464 |
|
|
return (NULL); |
465 |
|
|
bp = (char *)kd->procbase; |
466 |
|
|
|
467 |
|
|
/* allprocess */ |
468 |
|
|
if (KREAD(kd, nl[2].n_value, &pr)) { |
469 |
|
|
_kvm_err(kd, kd->program, "cannot read allprocess"); |
470 |
|
|
return (NULL); |
471 |
|
|
} |
472 |
|
|
nthreads = kvm_proclist(kd, op, arg, pr, bp, maxthread, esize); |
473 |
|
|
if (nthreads < 0) |
474 |
|
|
return (NULL); |
475 |
|
|
|
476 |
|
|
/* zombprocess */ |
477 |
|
|
if (KREAD(kd, nl[3].n_value, &pr)) { |
478 |
|
|
_kvm_err(kd, kd->program, "cannot read zombprocess"); |
479 |
|
|
return (NULL); |
480 |
|
|
} |
481 |
|
|
i = kvm_proclist(kd, op, arg, pr, bp + (esize * nthreads), |
482 |
|
|
maxthread - nthreads, esize); |
483 |
|
|
if (i > 0) |
484 |
|
|
nthreads += i; |
485 |
|
|
} |
486 |
|
|
if (kd->procbase != NULL) |
487 |
|
|
*cnt = nthreads; |
488 |
|
|
return (kd->procbase); |
489 |
|
|
} |