1 |
|
|
/* $OpenBSD: utils.c,v 1.25 2015/01/16 06:40:13 deraadt Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Top users/processes display for Unix |
5 |
|
|
* Version 3 |
6 |
|
|
* |
7 |
|
|
* Copyright (c) 1984, 1989, William LeFebvre, Rice University |
8 |
|
|
* Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University |
9 |
|
|
* |
10 |
|
|
* Redistribution and use in source and binary forms, with or without |
11 |
|
|
* modification, are permitted provided that the following conditions |
12 |
|
|
* are met: |
13 |
|
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
16 |
|
|
* notice, this list of conditions and the following disclaimer in the |
17 |
|
|
* documentation and/or other materials provided with the distribution. |
18 |
|
|
* |
19 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
20 |
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
21 |
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
22 |
|
|
* IN NO EVENT SHALL THE AUTHOR OR HIS EMPLOYER BE LIABLE FOR ANY DIRECT, INDIRECT, |
23 |
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
24 |
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 |
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 |
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 |
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
28 |
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 |
|
|
*/ |
30 |
|
|
|
31 |
|
|
/* |
32 |
|
|
* This file contains various handy utilities used by top. |
33 |
|
|
*/ |
34 |
|
|
|
35 |
|
|
#include <sys/types.h> |
36 |
|
|
#include <sys/sysctl.h> |
37 |
|
|
#include <err.h> |
38 |
|
|
#include <stdio.h> |
39 |
|
|
#include <string.h> |
40 |
|
|
#include <stdlib.h> |
41 |
|
|
#include <stdint.h> |
42 |
|
|
#include <limits.h> |
43 |
|
|
|
44 |
|
|
#include "top.h" |
45 |
|
|
#include "machine.h" |
46 |
|
|
#include "utils.h" |
47 |
|
|
|
48 |
|
|
int |
49 |
|
|
atoiwi(char *str) |
50 |
|
|
{ |
51 |
|
|
size_t len; |
52 |
|
|
const char *errstr; |
53 |
|
|
int i; |
54 |
|
|
|
55 |
|
|
len = strlen(str); |
56 |
|
|
if (len != 0) { |
57 |
|
|
if (strncmp(str, "infinity", len) == 0 || |
58 |
|
|
strncmp(str, "all", len) == 0 || |
59 |
|
|
strncmp(str, "maximum", len) == 0) { |
60 |
|
|
return (Infinity); |
61 |
|
|
} |
62 |
|
|
i = (int)strtonum(str, 0, INT_MAX, &errstr); |
63 |
|
|
if (errstr) { |
64 |
|
|
return (Invalid); |
65 |
|
|
} else |
66 |
|
|
return (i); |
67 |
|
|
} |
68 |
|
|
return (0); |
69 |
|
|
} |
70 |
|
|
|
71 |
|
|
/* |
72 |
|
|
* itoa - convert integer (decimal) to ascii string. |
73 |
|
|
*/ |
74 |
|
|
char * |
75 |
|
|
itoa(int val) |
76 |
|
|
{ |
77 |
|
|
static char buffer[16]; /* result is built here */ |
78 |
|
|
|
79 |
|
|
/* |
80 |
|
|
* 16 is sufficient since the largest number we will ever convert |
81 |
|
|
* will be 2^32-1, which is 10 digits. |
82 |
|
|
*/ |
83 |
|
|
(void)snprintf(buffer, sizeof(buffer), "%d", val); |
84 |
|
|
return (buffer); |
85 |
|
|
} |
86 |
|
|
|
87 |
|
|
/* |
88 |
|
|
* format_uid(uid) - like itoa, except for uid_t and the number is right |
89 |
|
|
* justified in a 6 character field to match uname_field in top.c. |
90 |
|
|
*/ |
91 |
|
|
char * |
92 |
|
|
format_uid(uid_t uid) |
93 |
|
|
{ |
94 |
|
|
static char buffer[16]; /* result is built here */ |
95 |
|
|
|
96 |
|
|
/* |
97 |
|
|
* 16 is sufficient since the largest uid we will ever convert |
98 |
|
|
* will be 2^32-1, which is 10 digits. |
99 |
|
|
*/ |
100 |
|
|
(void)snprintf(buffer, sizeof(buffer), "%6u", uid); |
101 |
|
|
return (buffer); |
102 |
|
|
} |
103 |
|
|
|
104 |
|
|
/* |
105 |
|
|
* digits(val) - return number of decimal digits in val. Only works for |
106 |
|
|
* positive numbers. If val <= 0 then digits(val) == 0. |
107 |
|
|
*/ |
108 |
|
|
int |
109 |
|
|
digits(int val) |
110 |
|
|
{ |
111 |
|
|
int cnt = 0; |
112 |
|
|
|
113 |
|
|
while (val > 0) { |
114 |
|
|
cnt++; |
115 |
|
|
val /= 10; |
116 |
|
|
} |
117 |
|
|
return (cnt); |
118 |
|
|
} |
119 |
|
|
|
120 |
|
|
/* |
121 |
|
|
* string_index(string, array) - find string in array and return index |
122 |
|
|
*/ |
123 |
|
|
int |
124 |
|
|
string_index(char *string, char **array) |
125 |
|
|
{ |
126 |
|
|
int i = 0; |
127 |
|
|
|
128 |
|
|
while (*array != NULL) { |
129 |
|
|
if (strncmp(string, *array, strlen(string)) == 0) |
130 |
|
|
return (i); |
131 |
|
|
array++; |
132 |
|
|
i++; |
133 |
|
|
} |
134 |
|
|
return (-1); |
135 |
|
|
} |
136 |
|
|
|
137 |
|
|
/* |
138 |
|
|
* argparse(line, cntp) - parse arguments in string "line", separating them |
139 |
|
|
* out into an argv-like array, and setting *cntp to the number of |
140 |
|
|
* arguments encountered. This is a simple parser that doesn't understand |
141 |
|
|
* squat about quotes. |
142 |
|
|
*/ |
143 |
|
|
char ** |
144 |
|
|
argparse(char *line, int *cntp) |
145 |
|
|
{ |
146 |
|
|
char **argv, **argarray, *args, *from, *to; |
147 |
|
|
int cnt, ch, length, lastch; |
148 |
|
|
|
149 |
|
|
/* |
150 |
|
|
* unfortunately, the only real way to do this is to go thru the |
151 |
|
|
* input string twice. |
152 |
|
|
*/ |
153 |
|
|
|
154 |
|
|
/* step thru the string counting the white space sections */ |
155 |
|
|
from = line; |
156 |
|
|
lastch = cnt = length = 0; |
157 |
|
|
while ((ch = *from++) != '\0') { |
158 |
|
|
length++; |
159 |
|
|
if (ch == ' ' && lastch != ' ') |
160 |
|
|
cnt++; |
161 |
|
|
lastch = ch; |
162 |
|
|
} |
163 |
|
|
|
164 |
|
|
/* |
165 |
|
|
* add three to the count: one for the initial "dummy" argument, one |
166 |
|
|
* for the last argument and one for NULL |
167 |
|
|
*/ |
168 |
|
|
cnt += 3; |
169 |
|
|
|
170 |
|
|
/* allocate a char * array to hold the pointers */ |
171 |
|
|
if ((argarray = calloc(cnt, sizeof(char *))) == NULL) |
172 |
|
|
err(1, NULL); |
173 |
|
|
|
174 |
|
|
/* allocate another array to hold the strings themselves */ |
175 |
|
|
if ((args = malloc(length + 2)) == NULL) |
176 |
|
|
err(1, NULL); |
177 |
|
|
|
178 |
|
|
/* initialization for main loop */ |
179 |
|
|
from = line; |
180 |
|
|
to = args; |
181 |
|
|
argv = argarray; |
182 |
|
|
lastch = '\0'; |
183 |
|
|
|
184 |
|
|
/* create a dummy argument to keep getopt happy */ |
185 |
|
|
*argv++ = to; |
186 |
|
|
*to++ = '\0'; |
187 |
|
|
cnt = 2; |
188 |
|
|
|
189 |
|
|
/* now build argv while copying characters */ |
190 |
|
|
*argv++ = to; |
191 |
|
|
while ((ch = *from++) != '\0') { |
192 |
|
|
if (ch != ' ') { |
193 |
|
|
if (lastch == ' ') { |
194 |
|
|
*to++ = '\0'; |
195 |
|
|
*argv++ = to; |
196 |
|
|
cnt++; |
197 |
|
|
} |
198 |
|
|
*to++ = ch; |
199 |
|
|
} |
200 |
|
|
lastch = ch; |
201 |
|
|
} |
202 |
|
|
*to++ = '\0'; |
203 |
|
|
|
204 |
|
|
/* set cntp and return the allocated array */ |
205 |
|
|
*cntp = cnt; |
206 |
|
|
return (argarray); |
207 |
|
|
} |
208 |
|
|
|
209 |
|
|
/* |
210 |
|
|
* percentages(cnt, out, new, old, diffs) - calculate percentage change |
211 |
|
|
* between array "old" and "new", putting the percentages in "out". |
212 |
|
|
* "cnt" is size of each array and "diffs" is used for scratch space. |
213 |
|
|
* The array "old" is updated on each call. |
214 |
|
|
* The routine assumes modulo arithmetic. This function is especially |
215 |
|
|
* useful on BSD machines for calculating cpu state percentages. |
216 |
|
|
*/ |
217 |
|
|
int |
218 |
|
|
percentages(int cnt, int64_t *out, int64_t *new, int64_t *old, int64_t *diffs) |
219 |
|
2 |
{ |
220 |
|
|
int64_t change, total_change, *dp, half_total; |
221 |
|
|
int i; |
222 |
|
|
|
223 |
|
|
/* initialization */ |
224 |
|
2 |
total_change = 0; |
225 |
|
2 |
dp = diffs; |
226 |
|
|
|
227 |
|
|
/* calculate changes for each state and the overall change */ |
228 |
✓✓ |
12 |
for (i = 0; i < cnt; i++) { |
229 |
✗✓ |
10 |
if ((change = *new - *old) < 0) { |
230 |
|
|
/* this only happens when the counter wraps */ |
231 |
|
|
change = INT64_MAX - *old + *new; |
232 |
|
|
} |
233 |
|
10 |
total_change += (*dp++ = change); |
234 |
|
10 |
*old++ = *new++; |
235 |
|
|
} |
236 |
|
|
|
237 |
|
|
/* avoid divide by zero potential */ |
238 |
✗✓ |
2 |
if (total_change == 0) |
239 |
|
|
total_change = 1; |
240 |
|
|
|
241 |
|
|
/* calculate percentages based on overall change, rounding up */ |
242 |
|
2 |
half_total = total_change / 2l; |
243 |
✓✓ |
12 |
for (i = 0; i < cnt; i++) |
244 |
|
10 |
*out++ = ((*diffs++ * 1000 + half_total) / total_change); |
245 |
|
|
|
246 |
|
|
/* return the total in case the caller wants to use it */ |
247 |
|
2 |
return (total_change); |
248 |
|
|
} |
249 |
|
|
|
250 |
|
|
/* |
251 |
|
|
* format_time(seconds) - format number of seconds into a suitable display |
252 |
|
|
* that will fit within 6 characters. Note that this routine builds its |
253 |
|
|
* string in a static area. If it needs to be called more than once without |
254 |
|
|
* overwriting previous data, then we will need to adopt a technique similar |
255 |
|
|
* to the one used for format_k. |
256 |
|
|
*/ |
257 |
|
|
|
258 |
|
|
/* |
259 |
|
|
* Explanation: We want to keep the output within 6 characters. For low |
260 |
|
|
* values we use the format mm:ss. For values that exceed 999:59, we switch |
261 |
|
|
* to a format that displays hours and fractions: hhh.tH. For values that |
262 |
|
|
* exceed 999.9, we use hhhh.t and drop the "H" designator. For values that |
263 |
|
|
* exceed 9999.9, we use "???". |
264 |
|
|
*/ |
265 |
|
|
|
266 |
|
|
char * |
267 |
|
|
format_time(time_t seconds) |
268 |
|
48 |
{ |
269 |
|
|
static char result[10]; |
270 |
|
|
|
271 |
|
|
/* sanity protection */ |
272 |
✗✓ |
48 |
if (seconds < 0 || seconds > (99999l * 360l)) { |
273 |
|
|
strlcpy(result, " ???", sizeof result); |
274 |
✗✓ |
48 |
} else if (seconds >= (1000l * 60l)) { |
275 |
|
|
/* alternate (slow) method displaying hours and tenths */ |
276 |
|
|
snprintf(result, sizeof(result), "%5.1fH", |
277 |
|
|
(double) seconds / (double) (60l * 60l)); |
278 |
|
|
|
279 |
|
|
/* |
280 |
|
|
* It is possible that the snprintf took more than 6 |
281 |
|
|
* characters. If so, then the "H" appears as result[6]. If |
282 |
|
|
* not, then there is a \0 in result[6]. Either way, it is |
283 |
|
|
* safe to step on. |
284 |
|
|
*/ |
285 |
|
|
result[6] = '\0'; |
286 |
|
|
} else { |
287 |
|
|
/* standard method produces MMM:SS */ |
288 |
|
|
/* we avoid printf as must as possible to make this quick */ |
289 |
|
48 |
snprintf(result, sizeof(result), "%3d:%02d", (int)seconds / 60, |
290 |
|
|
(int)seconds % 60); |
291 |
|
|
} |
292 |
|
48 |
return (result); |
293 |
|
|
} |
294 |
|
|
|
295 |
|
|
/* |
296 |
|
|
* format_k(amt) - format a kilobyte memory value, returning a string |
297 |
|
|
* suitable for display. Returns a pointer to a static |
298 |
|
|
* area that changes each call. "amt" is converted to a |
299 |
|
|
* string with a trailing "K". If "amt" is 10000 or greater, |
300 |
|
|
* then it is formatted as megabytes (rounded) with a |
301 |
|
|
* trailing "M". |
302 |
|
|
*/ |
303 |
|
|
|
304 |
|
|
/* |
305 |
|
|
* Compromise time. We need to return a string, but we don't want the |
306 |
|
|
* caller to have to worry about freeing a dynamically allocated string. |
307 |
|
|
* Unfortunately, we can't just return a pointer to a static area as one |
308 |
|
|
* of the common uses of this function is in a large call to snprintf where |
309 |
|
|
* it might get invoked several times. Our compromise is to maintain an |
310 |
|
|
* array of strings and cycle thru them with each invocation. We make the |
311 |
|
|
* array large enough to handle the above mentioned case. The constant |
312 |
|
|
* NUM_STRINGS defines the number of strings in this array: we can tolerate |
313 |
|
|
* up to NUM_STRINGS calls before we start overwriting old information. |
314 |
|
|
* Keeping NUM_STRINGS a power of two will allow an intelligent optimizer |
315 |
|
|
* to convert the modulo operation into something quicker. What a hack! |
316 |
|
|
*/ |
317 |
|
|
|
318 |
|
|
#define NUM_STRINGS 8 |
319 |
|
|
|
320 |
|
|
char * |
321 |
|
|
format_k(int amt) |
322 |
|
108 |
{ |
323 |
|
|
static char retarray[NUM_STRINGS][16]; |
324 |
|
|
static int idx = 0; |
325 |
|
108 |
char *ret, tag = 'K'; |
326 |
|
|
|
327 |
|
108 |
ret = retarray[idx]; |
328 |
|
108 |
idx = (idx + 1) % NUM_STRINGS; |
329 |
|
|
|
330 |
✓✓ |
108 |
if (amt >= 10000) { |
331 |
|
14 |
amt = (amt + 512) / 1024; |
332 |
|
14 |
tag = 'M'; |
333 |
✗✓ |
14 |
if (amt >= 10000) { |
334 |
|
|
amt = (amt + 512) / 1024; |
335 |
|
|
tag = 'G'; |
336 |
|
|
} |
337 |
|
|
} |
338 |
|
108 |
snprintf(ret, sizeof(retarray[0]), "%d%c", amt, tag); |
339 |
|
108 |
return (ret); |
340 |
|
|
} |
341 |
|
|
|
342 |
|
|
int |
343 |
|
|
find_pid(pid_t pid) |
344 |
|
|
{ |
345 |
|
|
struct kinfo_proc *pbase, *cur; |
346 |
|
|
int nproc; |
347 |
|
|
|
348 |
|
|
if ((pbase = getprocs(KERN_PROC_KTHREAD, 0, &nproc)) == NULL) |
349 |
|
|
quit(23); |
350 |
|
|
|
351 |
|
|
for (cur = pbase; cur < &pbase[nproc]; cur++) |
352 |
|
|
if (cur->p_pid == pid) |
353 |
|
|
return 1; |
354 |
|
|
return 0; |
355 |
|
|
} |