1 /* $OpenBSD: pigs.c,v 1.30 2015/09/12 15:59:36 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/param.h> /* MAXCOMLEN */ 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 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) < 0) 115 return (-1); 116 num_disp = pigs_cnt; 117 return (0); 118 } 119 120 121 int 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 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 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 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 254 showpigs(int k) 255 { 256 struct kinfo_proc *kp; 257 double value; 258 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 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