xref: /illumos-gate/usr/src/cmd/prstat/prutil.c (revision 726fad2a65f16c200a03969c29cb5c86c2d427db)
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