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