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