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
Warn(char * format,...)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
Die(char * format,...)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
Progname(char * arg0)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
Usage()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
Atoi(char * p)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
Format_size(char * str,size_t size,int length)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
Format_time(char * str,ulong_t time,int length)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
Format_pct(char * str,float val,int length)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
Format_num(char * str,int num,int length)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
Format_state(char * str,char state,processorid_t pr_id,int length)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 *
Realloc(void * ptr,size_t size)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 *
Malloc(size_t size)234 Malloc(size_t size)
235 {
236 return (Realloc(NULL, size));
237 }
238
239 void *
Zalloc(size_t size)240 Zalloc(size_t size)
241 {
242 return (memset(Realloc(NULL, size), 0, size));
243 }
244
245 int
Setrlimit()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
Priocntl(char * class)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
getprojname(projid_t projid,char * str,int len,int noresolve)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
getzonename(zoneid_t zoneid,char * str,int len)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
stripfname(char * buf)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