xref: /titanic_52/usr/src/cmd/prstat/prutil.c (revision d14abf155341d55053c76eeec58b787a456b753b)
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