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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/param.h> 31 #include <sys/resource.h> 32 #include <sys/priocntl.h> 33 #include <sys/rtpriocntl.h> 34 #include <sys/tspriocntl.h> 35 #include <zone.h> 36 37 #include <libintl.h> 38 #include <limits.h> 39 #include <wchar.h> 40 #include <unistd.h> 41 #include <string.h> 42 #include <stdlib.h> 43 #include <stdarg.h> 44 #include <stdio.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 [-acJLmRtTvZ] [-u euidlist] [-U uidlist]\n" 110 "\t[-p pidlist] [-P cpulist] [-C psrsetlist]\n" 111 "\t[-j projidlist] [-k taskidlist] [-z zoneidlist]\n" 112 "\t[-s key | -S key] [-n nprocs[,nusers]]\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 'X': 201 (void) strncpy(str, "xbrk", 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 if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) 256 return (fd_limit); 257 else 258 return (rlim.rlim_cur); 259 } 260 261 void 262 Priocntl(char *class) 263 { 264 pcinfo_t pcinfo; 265 pcparms_t pcparms; 266 (void) strcpy(pcinfo.pc_clname, class); 267 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) { 268 Warn(gettext("cannot get real time class parameters")); 269 return; 270 } 271 pcparms.pc_cid = pcinfo.pc_cid; 272 ((rtparms_t *)pcparms.pc_clparms)->rt_pri = 0; 273 ((rtparms_t *)pcparms.pc_clparms)->rt_tqsecs = 0; 274 ((rtparms_t *)pcparms.pc_clparms)->rt_tqnsecs = RT_NOCHANGE; 275 if (priocntl(P_PID, getpid(), PC_SETPARMS, (caddr_t)&pcparms) == -1) 276 Warn(gettext("cannot enter the real time class")); 277 } 278 279 void 280 getprojname(projid_t projid, char *str, int len) 281 { 282 struct project proj; 283 284 if (getprojbyid(projid, &proj, projbuf, PROJECT_BUFSZ) != NULL) 285 (void) snprintf(str, len, "%-28s", proj.pj_name); 286 else 287 (void) snprintf(str, len, "%-6d", (int)projid); 288 } 289 290 void 291 getzonename(zoneid_t zoneid, char *str, int len) 292 { 293 char zone_name[ZONENAME_MAX]; 294 295 if (getzonenamebyid(zoneid, zone_name, sizeof (zone_name)) < 0) 296 (void) snprintf(str, len, "%-6d", (int)zoneid); 297 else 298 (void) snprintf(str, len, "%-28s", zone_name); 299 } 300 301 /* 302 * Remove all unprintable characters from process name 303 */ 304 void 305 stripfname(char *buf) 306 { 307 int bytesleft = PRFNSZ; 308 wchar_t wchar; 309 int length; 310 char *cp; 311 312 buf[bytesleft - 1] = '\0'; 313 314 for (cp = buf; *cp != '\0'; cp += length) { 315 length = mbtowc(&wchar, cp, MB_LEN_MAX); 316 if (length <= 0) { 317 *cp = '\0'; 318 break; 319 } 320 if (!iswprint(wchar)) { 321 if (bytesleft <= length) { 322 *cp = '\0'; 323 break; 324 } 325 (void) memmove(cp, cp + length, bytesleft - length); 326 length = 0; 327 } 328 bytesleft -= length; 329 } 330 } 331