1177633Sdfr/*	$OpenBSD: pigs.c,v 1.33 2022/02/22 17:35:01 deraadt Exp $	*/
2177633Sdfr/*	$NetBSD: pigs.c,v 1.3 1995/04/29 05:54:50 cgd Exp $	*/
3261046Smav
4261046Smav/*-
5261046Smav * Copyright (c) 1980, 1992, 1993
6261046Smav *	The Regents of the University of California.  All rights reserved.
7261046Smav *
8261046Smav * Redistribution and use in source and binary forms, with or without
9261046Smav * modification, are permitted provided that the following conditions
10261046Smav * are met:
11261046Smav * 1. Redistributions of source code must retain the above copyright
12261046Smav *    notice, this list of conditions and the following disclaimer.
13261046Smav * 2. Redistributions in binary form must reproduce the above copyright
14261046Smav *    notice, this list of conditions and the following disclaimer in the
15261046Smav *    documentation and/or other materials provided with the distribution.
16261046Smav * 3. Neither the name of the University nor the names of its contributors
17177633Sdfr *    may be used to endorse or promote products derived from this software
18261046Smav *    without specific prior written permission.
19261046Smav *
20261046Smav * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21261046Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23261046Smav * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24261046Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25261046Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26261046Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27261046Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28261046Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29177633Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30177633Sdfr * SUCH DAMAGE.
31177633Sdfr */
32177633Sdfr
33177633Sdfr/*
34177633Sdfr * Pigs display from Bill Reeves at Lucasfilm
35177633Sdfr */
36177633Sdfr
37177633Sdfr#include <sys/types.h>
38177633Sdfr#include <sys/signal.h>
39177633Sdfr#include <sys/proc.h>
40177633Sdfr#include <sys/resource.h>
41177633Sdfr#include <sys/sched.h>
42177633Sdfr#include <sys/sysctl.h>
43177633Sdfr#include <sys/time.h>
44177633Sdfr
45177633Sdfr#include <curses.h>
46177633Sdfr#include <math.h>
47177633Sdfr#include <pwd.h>
48177633Sdfr#include <err.h>
49177633Sdfr#include <stdlib.h>
50193650Srwatson#include <string.h>
51177633Sdfr
52177633Sdfr#include "systat.h"
53177633Sdfr
54177633Sdfrint compar(const void *, const void *);
55184588Sdfrvoid print_pg(void);
56184588Sdfrint read_pg(void);
57184588Sdfrint select_pg(void);
58184588Sdfrvoid showpigs(int k);
59184588Sdfr
60184588Sdfrstatic struct kinfo_proc *procbase = NULL;
61184588Sdfrstatic int nproc, pigs_cnt, *pb_indices = NULL;
62177633Sdfrstatic int onproc = -1;
63177633Sdfr
64177633Sdfrstatic long stime[CPUSTATES];
65177633Sdfrstatic double  lccpu;
66177633Sdfrstruct loadavg sysload;
67177633Sdfr
68177633Sdfr
69177633Sdfr
70177633Sdfrfield_def fields_pg[] = {
71177633Sdfr	{"USER", 6, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
72177633Sdfr	{"NAME", 10, 24, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
73177633Sdfr	{"PID", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
74177633Sdfr	{"CPU", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
75177633Sdfr	{"", 30, 60, 1, FLD_ALIGN_BAR, -1, 0, 0, 100},
76177633Sdfr};
77177633Sdfr
78177633Sdfr#define FLD_PG_USER	FIELD_ADDR(fields_pg,0)
79177633Sdfr#define FLD_PG_NAME	FIELD_ADDR(fields_pg,1)
80177633Sdfr#define FLD_PG_PID	FIELD_ADDR(fields_pg,2)
81177633Sdfr#define FLD_PG_VALUE	FIELD_ADDR(fields_pg,3)
82177633Sdfr#define FLD_PG_BAR	FIELD_ADDR(fields_pg,4)
83177633Sdfr
84177633Sdfr/* Define views */
85177633Sdfrfield_def *view_pg_0[] = {
86177633Sdfr	FLD_PG_PID, FLD_PG_USER, FLD_PG_NAME, FLD_PG_VALUE, FLD_PG_BAR, NULL
87184588Sdfr};
88184588Sdfr
89177633Sdfr
90177633Sdfr/* Define view managers */
91177633Sdfrstruct view_manager pigs_mgr = {
92177633Sdfr	"Pigs", select_pg, read_pg, NULL, print_header,
93177633Sdfr	print_pg, keyboard_callback, NULL, NULL
94177633Sdfr};
95177633Sdfr
96177633Sdfrfield_view views_pg[] = {
97177633Sdfr	{view_pg_0, "pigs", '5', &pigs_mgr},
98177633Sdfr	{NULL, NULL, 0, NULL}
99177633Sdfr};
100184588Sdfr
101184588Sdfrint	fscale;
102184588Sdfr
103184588Sdfr#define pctdouble(p) ((double)(p) / fscale)
104184588Sdfr
105177633Sdfrtypedef long pctcpu;
106177633Sdfr
107177633Sdfrint
108177633Sdfrselect_pg(void)
109177633Sdfr{
110177633Sdfr	int mib[] = { CTL_KERN, KERN_FSCALE };
111177633Sdfr	size_t size = sizeof(fscale);
112184588Sdfr
113184588Sdfr        if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
114184588Sdfr            &fscale, &size, NULL, 0) == -1)
115184588Sdfr                return (-1);
116184588Sdfr	num_disp = pigs_cnt;
117184588Sdfr	return (0);
118184588Sdfr}
119184588Sdfr
120184588Sdfr
121184588Sdfrint
122184588Sdfrgetprocs(void)
123184588Sdfr{
124184588Sdfr	size_t size;
125184588Sdfr	int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_KTHREAD, 0, sizeof(struct kinfo_proc), 0};
126184588Sdfr
127184588Sdfr	int st;
128184588Sdfr
129184588Sdfr	free(procbase);
130184588Sdfr	procbase = NULL;
131184588Sdfr
132184588Sdfr	st = sysctl(mib, 6, NULL, &size, NULL, 0);
133184588Sdfr	if (st == -1)
134184588Sdfr		return (1);
135184588Sdfr
136184588Sdfr	size = 5 * size / 4;		/* extra slop */
137184588Sdfr	if ((procbase = malloc(size + 1)) == NULL)
138184588Sdfr		return (1);
139184588Sdfr
140184588Sdfr	mib[5] = (int)(size / sizeof(struct kinfo_proc));
141184588Sdfr	st = sysctl(mib, 6, procbase, &size, NULL, 0);
142177633Sdfr	if (st == -1)
143177633Sdfr		return (1);
144177633Sdfr
145177633Sdfr	nproc = (int)(size / sizeof(struct kinfo_proc));
146184588Sdfr	return (0);
147184588Sdfr}
148177633Sdfr
149177633Sdfr
150177633Sdfrint
151177633Sdfrread_pg(void)
152184588Sdfr{
153184588Sdfr	static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME };
154184588Sdfr	long ctimes[CPUSTATES];
155177633Sdfr	double t;
156184588Sdfr	int i, k;
157184588Sdfr	size_t size;
158184588Sdfr
159184588Sdfr	num_disp = pigs_cnt = 0;
160184588Sdfr
161184588Sdfr	if (getprocs()) {
162184588Sdfr		error("Failed to read process info!");
163184588Sdfr		return 1;
164184588Sdfr	}
165184588Sdfr
166184588Sdfr	if (nproc > onproc) {
167184588Sdfr		int *p;
168194498Sbrooks		p = reallocarray(pb_indices, nproc + 1, sizeof(int));
169177633Sdfr		if (p == NULL) {
170177633Sdfr			error("Out of Memory!");
171177633Sdfr			return 1;
172177633Sdfr		}
173177633Sdfr		pb_indices = p;
174177633Sdfr		onproc = nproc;
175177633Sdfr	}
176177633Sdfr
177177633Sdfr	memset(&procbase[nproc], 0, sizeof(*procbase));
178184588Sdfr
179177633Sdfr	for (i = 0; i <= nproc; i++)
180194498Sbrooks		pb_indices[i] = i;
181184588Sdfr
182193650Srwatson	/*
183193650Srwatson	 * and for the imaginary "idle" process
184184588Sdfr	 */
185177633Sdfr	size = sizeof(ctimes);
186177633Sdfr	sysctl(cp_time_mib, 2, &ctimes, &size, NULL, 0);
187184588Sdfr
188184588Sdfr	t = 0;
189184588Sdfr	for (i = 0; i < CPUSTATES; i++)
190184588Sdfr		t += ctimes[i] - stime[i];
191184588Sdfr	if (t == 0.0)
192177633Sdfr		t = 1.0;
193177633Sdfr
194177633Sdfr	procbase[nproc].p_pctcpu = (ctimes[CP_IDLE] - stime[CP_IDLE]) / t / pctdouble(1);
195177633Sdfr	for (i = 0; i < CPUSTATES; i++)
196177633Sdfr		stime[i] = ctimes[i];
197
198	qsort(pb_indices, nproc + 1, sizeof (int), compar);
199
200	pigs_cnt = 0;
201	for (k = 0; k < nproc + 1; k++) {
202		int j = pb_indices[k];
203		if (pctdouble(procbase[j].p_pctcpu) < 0.01)
204			break;
205		pigs_cnt++;
206	}
207
208	num_disp = pigs_cnt;
209	return 0;
210}
211
212
213void
214print_pg(void)
215{
216	int n, count = 0;
217
218	for (n = dispstart; n < num_disp; n++) {
219		showpigs(pb_indices[n]);
220		count++;
221		if (maxprint > 0 && count >= maxprint)
222			break;
223	}
224}
225
226int
227initpigs(void)
228{
229	static int sysload_mib[] = {CTL_VM, VM_LOADAVG};
230	static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME };
231	static int ccpu_mib[] = { CTL_KERN, KERN_CCPU };
232	field_view *v;
233	size_t size;
234	fixpt_t ccpu;
235
236	size = sizeof(stime);
237	sysctl(cp_time_mib, 2, &stime, &size, NULL, 0);
238
239	size = sizeof(sysload);
240	sysctl(sysload_mib, 2, &sysload, &size, NULL, 0);
241
242	size = sizeof(ccpu);
243	sysctl(ccpu_mib, 2, &ccpu, &size, NULL, 0);
244
245	lccpu = log((double) ccpu / sysload.fscale);
246
247	for (v = views_pg; v->name != NULL; v++)
248		add_view(v);
249
250	return(1);
251}
252
253void
254showpigs(int k)
255{
256	struct kinfo_proc *kp;
257	double value;
258	const char *uname, *pname;
259
260	if (procbase == NULL)
261		return;
262
263	value = pctdouble(procbase[k].p_pctcpu) * 100;
264
265	kp = &procbase[k];
266	if (kp->p_comm[0] == '\0') {
267		uname = "";
268		pname = "<idle>";
269	} else {
270		uname = user_from_uid(kp->p_uid, 0);
271		pname = kp->p_comm;
272		print_fld_uint(FLD_PG_PID, kp->p_pid);
273	}
274
275	tb_start();
276	tbprintf("%.2f", value);
277	print_fld_tb(FLD_PG_VALUE);
278
279	print_fld_str(FLD_PG_NAME, pname);
280	print_fld_str(FLD_PG_USER, uname);
281	print_fld_bar(FLD_PG_BAR, value);
282
283	end_line();
284}
285
286
287int
288compar(const void *a, const void *b)
289{
290	int i1 = *((int *)a);
291	int i2 = *((int *)b);
292
293	return procbase[i1].p_pctcpu >
294		procbase[i2].p_pctcpu ? -1 : 1;
295}
296
297