xref: /illumos-gate/usr/src/cmd/prstat/prutil.c (revision 52244c09)
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 }
354