GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libkvm/kvm_proc2.c Lines: 28 217 12.9 %
Date: 2017-11-07 Branches: 7 201 3.5 %

Line Branch Exec Source
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
4108
	int mib[6], st, nthreads;
387
	void *procbase;
388
2054
	size_t size;
389
390
2054
	if ((ssize_t)esize < 0)
391
		return (NULL);
392
393
2054
	if (ISALIVE(kd)) {
394
2054
		size = 0;
395
2054
		mib[0] = CTL_KERN;
396
2054
		mib[1] = KERN_PROC;
397
2054
		mib[2] = op;
398
2054
		mib[3] = arg;
399
2054
		mib[4] = esize;
400
401
2054
		do {
402
2054
			mib[5] = 0;
403
2054
			st = sysctl(mib, 6, NULL, &size, NULL, 0);
404
2054
			if (st == -1) {
405
				_kvm_syserr(kd, kd->program, "kvm_getprocs");
406
				return (NULL);
407
			}
408
409
2054
			size += size / 8; /* add ~10% */
410
411
2054
			procbase = _kvm_realloc(kd, kd->procbase, size);
412
2054
			if (procbase == NULL)
413
				return (NULL);
414
415
2054
			kd->procbase = procbase;
416
417
2054
			mib[5] = size / esize;
418
2054
			st = sysctl(mib, 6, kd->procbase, &size, NULL, 0);
419

2054
			if (st == -1 && errno != ENOMEM) {
420
				_kvm_syserr(kd, kd->program, "kvm_getprocs");
421
				return (NULL);
422
			}
423
2054
		} while (st == -1);
424
425
2054
		nthreads = size / esize;
426
2054
	} 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
2054
	if (kd->procbase != NULL)
487
2054
		*cnt = nthreads;
488
2054
	return (kd->procbase);
489
2054
}