1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2013 Gary Mills 23 * 24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 * 27 * Portions Copyright 2009 Chad Mynhier 28 */ 29 30 #include <sys/types.h> 31 #include <sys/param.h> 32 #include <sys/resource.h> 33 #include <sys/priocntl.h> 34 #include <sys/rtpriocntl.h> 35 #include <sys/tspriocntl.h> 36 #include <zone.h> 37 38 #include <libintl.h> 39 #include <limits.h> 40 #include <wchar.h> 41 #include <unistd.h> 42 #include <string.h> 43 #include <stdlib.h> 44 #include <stdarg.h> 45 #include <stdio.h> 46 #include <stdio_ext.h> 47 #include <errno.h> 48 #include <ctype.h> 49 #include <poll.h> 50 #include <project.h> 51 52 #include "prfile.h" 53 #include "prstat.h" 54 #include "prutil.h" 55 56 static char PRG_FMT[] = "%s: "; 57 static char ERR_FMT[] = ": %s\n"; 58 static char *progname; 59 static char projbuf[PROJECT_BUFSZ]; 60 61 #define RLIMIT_NOFILE_MAX 32767 62 63 /*PRINTFLIKE1*/ 64 void 65 Warn(char *format, ...) 66 { 67 int err = errno; 68 va_list alist; 69 70 if (progname != NULL) 71 (void) fprintf(stderr, PRG_FMT, progname); 72 va_start(alist, format); 73 (void) vfprintf(stderr, format, alist); 74 va_end(alist); 75 if (strchr(format, '\n') == NULL) 76 (void) fprintf(stderr, gettext(ERR_FMT), strerror(err)); 77 } 78 79 /*PRINTFLIKE1*/ 80 void 81 Die(char *format, ...) 82 { 83 int err = errno; 84 va_list alist; 85 86 if (progname != NULL) 87 (void) fprintf(stderr, PRG_FMT, progname); 88 va_start(alist, format); 89 (void) vfprintf(stderr, format, alist); 90 va_end(alist); 91 if (strchr(format, '\n') == NULL) 92 (void) fprintf(stderr, gettext(ERR_FMT), strerror(err)); 93 exit(1); 94 } 95 96 void 97 Progname(char *arg0) 98 { 99 char *p = strrchr(arg0, '/'); 100 if (p == NULL) 101 p = arg0; 102 else 103 p++; 104 progname = p; 105 } 106 107 void 108 Usage() 109 { 110 (void) fprintf(stderr, gettext( 111 "Usage:\tprstat [-acHJLmrRtTvWZ] [-u euidlist] [-U uidlist]\n" 112 "\t[-p pidlist] [-P cpulist] [-C psrsetlist] [-h lgrouplist]\n" 113 "\t[-j projidlist] [-k taskidlist] [-z zoneidlist]\n" 114 "\t[-s key | -S key] [-n nprocs[,nusers]] [-d d|u]\n" 115 "\t[interval [counter]]\n")); 116 exit(1); 117 } 118 119 int 120 Atoi(char *p) 121 { 122 int i; 123 char *q; 124 errno = 0; 125 i = (int)strtol(p, &q, 10); 126 if (errno != 0 || q == p || i < 0 || *q != '\0') 127 Die(gettext("illegal argument -- %s\n"), p); 128 /*NOTREACHED*/ 129 else 130 return (i); 131 return (0); /* keep gcc happy */ 132 } 133 134 void 135 Format_size(char *str, size_t size, int length) 136 { 137 char tag = 'K'; 138 if (size >= 10000) { 139 size = (size + 512) / 1024; 140 tag = 'M'; 141 if (size >= 10000) { 142 size = (size + 512) / 1024; 143 tag = 'G'; 144 } 145 } 146 (void) snprintf(str, length, "%4d%c", (int)size, tag); 147 } 148 149 void 150 Format_time(char *str, ulong_t time, int length) 151 { 152 (void) snprintf(str, length, gettext("%3d:%2.2d:%2.2d"), /* hr:mm:ss */ 153 (int)time/3600, (int)(time % 3600)/60, (int)time % 60); 154 } 155 156 void 157 Format_pct(char *str, float val, int length) 158 { 159 if (val > (float)100) 160 val = 100; 161 if (val < 0) 162 val = 0; 163 164 if (val < (float)9.95) 165 (void) snprintf(str, length, "%1.1f", val); 166 else 167 (void) snprintf(str, length, "%.0f", val); 168 } 169 170 void 171 Format_num(char *str, int num, int length) 172 { 173 if (num >= 100000) { 174 (void) snprintf(str, length, ".%1dM", num/100000); 175 } else { 176 if (num >= 1000) 177 (void) snprintf(str, length, "%2dK", num/1000); 178 else 179 (void) snprintf(str, length, "%3d", num); 180 } 181 } 182 183 void 184 Format_state(char *str, char state, processorid_t pr_id, int length) 185 { 186 switch (state) { 187 case 'S': 188 (void) strncpy(str, "sleep", length); 189 break; 190 case 'R': 191 (void) strncpy(str, "run", length); 192 break; 193 case 'Z': 194 (void) strncpy(str, "zombie", length); 195 break; 196 case 'T': 197 (void) strncpy(str, "stop", length); 198 break; 199 case 'I': 200 (void) strncpy(str, "idle", length); 201 break; 202 case 'W': 203 (void) strncpy(str, "wait", length); 204 break; 205 case 'O': 206 (void) snprintf(str, length, "cpu%-3d", (int)pr_id); 207 break; 208 default: 209 (void) strncpy(str, "?", length); 210 break; 211 } 212 } 213 214 void * 215 Realloc(void *ptr, size_t size) 216 { 217 int cnt = 0; 218 void *sav = ptr; 219 220 eagain: if ((ptr = realloc(ptr, size))) 221 return (ptr); 222 223 if ((++cnt <= 3) && (errno == EAGAIN)) { 224 Warn(gettext("realloc() failed, attempt %d"), cnt); 225 (void) poll(NULL, 0, 5000); /* wait for 5 seconds */ 226 ptr = sav; 227 goto eagain; 228 } 229 ptr = sav; 230 Die(gettext("not enough memory")); 231 /*NOTREACHED*/ 232 return (NULL); /* keep gcc happy */ 233 } 234 235 void * 236 Malloc(size_t size) 237 { 238 return (Realloc(NULL, size)); 239 } 240 241 void * 242 Zalloc(size_t size) 243 { 244 return (memset(Realloc(NULL, size), 0, size)); 245 } 246 247 int 248 Setrlimit() 249 { 250 struct rlimit rlim; 251 int fd_limit; 252 if (getrlimit(RLIMIT_NOFILE, &rlim) == -1) 253 Die(gettext("getrlimit failed")); 254 fd_limit = rlim.rlim_cur; 255 rlim.rlim_max = MIN(rlim.rlim_max, RLIMIT_NOFILE_MAX); 256 rlim.rlim_cur = rlim.rlim_max; 257 (void) enable_extended_FILE_stdio(-1, -1); 258 if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) 259 return (fd_limit); 260 else 261 return (rlim.rlim_cur); 262 } 263 264 void 265 Priocntl(char *class) 266 { 267 pcinfo_t pcinfo; 268 pcparms_t pcparms; 269 (void) strcpy(pcinfo.pc_clname, class); 270 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) { 271 Warn(gettext("cannot get real time class parameters")); 272 return; 273 } 274 pcparms.pc_cid = pcinfo.pc_cid; 275 ((rtparms_t *)pcparms.pc_clparms)->rt_pri = 0; 276 ((rtparms_t *)pcparms.pc_clparms)->rt_tqsecs = 0; 277 ((rtparms_t *)pcparms.pc_clparms)->rt_tqnsecs = RT_NOCHANGE; 278 if (priocntl(P_PID, getpid(), PC_SETPARMS, (caddr_t)&pcparms) == -1) 279 Warn(gettext("cannot enter the real time class")); 280 } 281 282 void 283 getprojname(projid_t projid, char *str, size_t len, int noresolve, 284 int trunc, size_t width) 285 { 286 struct project proj; 287 size_t n; 288 289 if (noresolve || getprojbyid(projid, &proj, projbuf, PROJECT_BUFSZ) == 290 NULL) { 291 (void) snprintf(str, len, "%-6d", (int)projid); 292 } else { 293 n = mbstowcs(NULL, proj.pj_name, 0); 294 if (n == (size_t)-1) 295 (void) snprintf(str, len, "%-28s", "ERROR"); 296 else if (trunc && n > width) 297 (void) snprintf(str, len, "%.*s%c", width - 1, 298 proj.pj_name, '*'); 299 else 300 (void) snprintf(str, len, "%-28s", proj.pj_name); 301 } 302 } 303 304 void 305 getzonename(zoneid_t zoneid, char *str, size_t len, int trunc, size_t width) 306 { 307 char zone_name[ZONENAME_MAX]; 308 size_t n; 309 310 if (getzonenamebyid(zoneid, zone_name, sizeof (zone_name)) < 0) { 311 (void) snprintf(str, len, "%-6d", (int)zoneid); 312 } else { 313 n = mbstowcs(NULL, zone_name, 0); 314 if (n == (size_t)-1) 315 (void) snprintf(str, len, "%-28s", "ERROR"); 316 else if (trunc && n > width) 317 (void) snprintf(str, len, "%.*s%c", width - 1, 318 zone_name, '*'); 319 else 320 (void) snprintf(str, len, "%-28s", zone_name); 321 } 322 } 323 324 /* 325 * Remove all unprintable characters from process name 326 */ 327 void 328 stripfname(char *buf) 329 { 330 int bytesleft = PRFNSZ; 331 wchar_t wchar; 332 int length; 333 char *cp; 334 335 buf[bytesleft - 1] = '\0'; 336 337 for (cp = buf; *cp != '\0'; cp += length) { 338 length = mbtowc(&wchar, cp, MB_LEN_MAX); 339 if (length <= 0) { 340 *cp = '\0'; 341 break; 342 } 343 if (!iswprint(wchar)) { 344 if (bytesleft <= length) { 345 *cp = '\0'; 346 break; 347 } 348 (void) memmove(cp, cp + length, bytesleft - length); 349 length = 0; 350 } 351 bytesleft -= length; 352 } 353 }