1 /* $OpenBSD: pigs.c,v 1.33 2022/02/22 17:35:01 deraadt Exp $ */
2 /* $NetBSD: pigs.c,v 1.3 1995/04/29 05:54:50 cgd Exp $ */
3
4 /*-
5 * Copyright (c) 1980, 1992, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * Pigs display from Bill Reeves at Lucasfilm
35 */
36
37 #include <sys/types.h>
38 #include <sys/signal.h>
39 #include <sys/proc.h>
40 #include <sys/resource.h>
41 #include <sys/sched.h>
42 #include <sys/sysctl.h>
43 #include <sys/time.h>
44
45 #include <curses.h>
46 #include <math.h>
47 #include <pwd.h>
48 #include <err.h>
49 #include <stdlib.h>
50 #include <string.h>
51
52 #include "systat.h"
53
54 int compar(const void *, const void *);
55 void print_pg(void);
56 int read_pg(void);
57 int select_pg(void);
58 void showpigs(int k);
59
60 static struct kinfo_proc *procbase = NULL;
61 static int nproc, pigs_cnt, *pb_indices = NULL;
62 static int onproc = -1;
63
64 static long stime[CPUSTATES];
65 static double lccpu;
66 struct loadavg sysload;
67
68
69
70 field_def fields_pg[] = {
71 {"USER", 6, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
72 {"NAME", 10, 24, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
73 {"PID", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
74 {"CPU", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
75 {"", 30, 60, 1, FLD_ALIGN_BAR, -1, 0, 0, 100},
76 };
77
78 #define FLD_PG_USER FIELD_ADDR(fields_pg,0)
79 #define FLD_PG_NAME FIELD_ADDR(fields_pg,1)
80 #define FLD_PG_PID FIELD_ADDR(fields_pg,2)
81 #define FLD_PG_VALUE FIELD_ADDR(fields_pg,3)
82 #define FLD_PG_BAR FIELD_ADDR(fields_pg,4)
83
84 /* Define views */
85 field_def *view_pg_0[] = {
86 FLD_PG_PID, FLD_PG_USER, FLD_PG_NAME, FLD_PG_VALUE, FLD_PG_BAR, NULL
87 };
88
89
90 /* Define view managers */
91 struct view_manager pigs_mgr = {
92 "Pigs", select_pg, read_pg, NULL, print_header,
93 print_pg, keyboard_callback, NULL, NULL
94 };
95
96 field_view views_pg[] = {
97 {view_pg_0, "pigs", '5', &pigs_mgr},
98 {NULL, NULL, 0, NULL}
99 };
100
101 int fscale;
102
103 #define pctdouble(p) ((double)(p) / fscale)
104
105 typedef long pctcpu;
106
107 int
select_pg(void)108 select_pg(void)
109 {
110 int mib[] = { CTL_KERN, KERN_FSCALE };
111 size_t size = sizeof(fscale);
112
113 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
114 &fscale, &size, NULL, 0) == -1)
115 return (-1);
116 num_disp = pigs_cnt;
117 return (0);
118 }
119
120
121 int
getprocs(void)122 getprocs(void)
123 {
124 size_t size;
125 int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_KTHREAD, 0, sizeof(struct kinfo_proc), 0};
126
127 int st;
128
129 free(procbase);
130 procbase = NULL;
131
132 st = sysctl(mib, 6, NULL, &size, NULL, 0);
133 if (st == -1)
134 return (1);
135
136 size = 5 * size / 4; /* extra slop */
137 if ((procbase = malloc(size + 1)) == NULL)
138 return (1);
139
140 mib[5] = (int)(size / sizeof(struct kinfo_proc));
141 st = sysctl(mib, 6, procbase, &size, NULL, 0);
142 if (st == -1)
143 return (1);
144
145 nproc = (int)(size / sizeof(struct kinfo_proc));
146 return (0);
147 }
148
149
150 int
read_pg(void)151 read_pg(void)
152 {
153 static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME };
154 long ctimes[CPUSTATES];
155 double t;
156 int i, k;
157 size_t size;
158
159 num_disp = pigs_cnt = 0;
160
161 if (getprocs()) {
162 error("Failed to read process info!");
163 return 1;
164 }
165
166 if (nproc > onproc) {
167 int *p;
168 p = reallocarray(pb_indices, nproc + 1, sizeof(int));
169 if (p == NULL) {
170 error("Out of Memory!");
171 return 1;
172 }
173 pb_indices = p;
174 onproc = nproc;
175 }
176
177 memset(&procbase[nproc], 0, sizeof(*procbase));
178
179 for (i = 0; i <= nproc; i++)
180 pb_indices[i] = i;
181
182 /*
183 * and for the imaginary "idle" process
184 */
185 size = sizeof(ctimes);
186 sysctl(cp_time_mib, 2, &ctimes, &size, NULL, 0);
187
188 t = 0;
189 for (i = 0; i < CPUSTATES; i++)
190 t += ctimes[i] - stime[i];
191 if (t == 0.0)
192 t = 1.0;
193
194 procbase[nproc].p_pctcpu = (ctimes[CP_IDLE] - stime[CP_IDLE]) / t / pctdouble(1);
195 for (i = 0; i < CPUSTATES; i++)
196 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
213 void
print_pg(void)214 print_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
226 int
initpigs(void)227 initpigs(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
253 void
showpigs(int k)254 showpigs(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
287 int
compar(const void * a,const void * b)288 compar(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