1
2
3
4
5
6
7
8
9
10
11
12#include "libbb.h"
13
14
15typedef struct unsigned_to_name_map_t {
16 long id;
17 char name[USERNAME_MAX_SIZE];
18} unsigned_to_name_map_t;
19
20typedef struct cache_t {
21 unsigned_to_name_map_t *cache;
22 int size;
23} cache_t;
24
25static cache_t username, groupname;
26
27static void clear_cache(cache_t *cp)
28{
29 free(cp->cache);
30 cp->cache = NULL;
31 cp->size = 0;
32}
33void FAST_FUNC clear_username_cache(void)
34{
35 clear_cache(&username);
36 clear_cache(&groupname);
37}
38
39#if 0
40
41
42static int get_cached(cache_t *cp, unsigned id)
43{
44 int i;
45 for (i = 0; i < cp->size; i++)
46 if (cp->cache[i].id == id)
47 return i;
48 i = cp->size++;
49 cp->cache = xrealloc_vector(cp->cache, 2, i);
50 cp->cache[i++].id = id;
51 return -i;
52}
53#endif
54
55static char* get_cached(cache_t *cp, long id,
56 char* FAST_FUNC x2x_utoa(long id))
57{
58 int i;
59 for (i = 0; i < cp->size; i++)
60 if (cp->cache[i].id == id)
61 return cp->cache[i].name;
62 i = cp->size++;
63 cp->cache = xrealloc_vector(cp->cache, 2, i);
64 cp->cache[i].id = id;
65
66 safe_strncpy(cp->cache[i].name, x2x_utoa(id), sizeof(cp->cache[i].name));
67 return cp->cache[i].name;
68}
69const char* FAST_FUNC get_cached_username(uid_t uid)
70{
71 return get_cached(&username, uid, uid2uname_utoa);
72}
73const char* FAST_FUNC get_cached_groupname(gid_t gid)
74{
75 return get_cached(&groupname, gid, gid2group_utoa);
76}
77
78
79#define PROCPS_BUFSIZE 1024
80
81static int read_to_buf(const char *filename, void *buf)
82{
83 int fd;
84
85
86 ssize_t ret = -1;
87 fd = open(filename, O_RDONLY);
88 if (fd >= 0) {
89 ret = read(fd, buf, PROCPS_BUFSIZE-1);
90 close(fd);
91 }
92 ((char *)buf)[ret > 0 ? ret : 0] = '\0';
93 return ret;
94}
95
96static procps_status_t* FAST_FUNC alloc_procps_scan(void)
97{
98 unsigned n = getpagesize();
99 procps_status_t* sp = xzalloc(sizeof(procps_status_t));
100 sp->dir = xopendir("/proc");
101 while (1) {
102 n >>= 1;
103 if (!n) break;
104 sp->shift_pages_to_bytes++;
105 }
106 sp->shift_pages_to_kb = sp->shift_pages_to_bytes - 10;
107 return sp;
108}
109
110void FAST_FUNC free_procps_scan(procps_status_t* sp)
111{
112 closedir(sp->dir);
113 free(sp->argv0);
114 USE_SELINUX(free(sp->context);)
115 free(sp);
116}
117
118#if ENABLE_FEATURE_TOPMEM
119static unsigned long fast_strtoul_16(char **endptr)
120{
121 unsigned char c;
122 char *str = *endptr;
123 unsigned long n = 0;
124
125 while ((c = *str++) != ' ') {
126 c = ((c|0x20) - '0');
127 if (c > 9)
128
129 c = c - ('a' - '0' - 10);
130 n = n*16 + c;
131 }
132 *endptr = str;
133 return n;
134}
135
136#undef ENABLE_FEATURE_FAST_TOP
137#define ENABLE_FEATURE_FAST_TOP 1
138#endif
139
140#if ENABLE_FEATURE_FAST_TOP
141
142static unsigned long fast_strtoul_10(char **endptr)
143{
144 char c;
145 char *str = *endptr;
146 unsigned long n = *str - '0';
147
148 while ((c = *++str) != ' ')
149 n = n*10 + (c - '0');
150
151 *endptr = str + 1;
152 return n;
153}
154static char *skip_fields(char *str, int count)
155{
156 do {
157 while (*str++ != ' ')
158 continue;
159
160 } while (--count);
161 return str;
162}
163#endif
164
165void BUG_comm_size(void);
166procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
167{
168 struct dirent *entry;
169 char buf[PROCPS_BUFSIZE];
170 char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
171 char *filename_tail;
172 long tasknice;
173 unsigned pid;
174 int n;
175 struct stat sb;
176
177 if (!sp)
178 sp = alloc_procps_scan();
179
180 for (;;) {
181 entry = readdir(sp->dir);
182 if (entry == NULL) {
183 free_procps_scan(sp);
184 return NULL;
185 }
186 pid = bb_strtou(entry->d_name, NULL, 10);
187 if (errno)
188 continue;
189
190
191
192
193
194 memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz));
195
196 sp->pid = pid;
197 if (!(flags & ~PSSCAN_PID)) break;
198
199#if ENABLE_SELINUX
200 if (flags & PSSCAN_CONTEXT) {
201 if (getpidcon(sp->pid, &sp->context) < 0)
202 sp->context = NULL;
203 }
204#endif
205
206 filename_tail = filename + sprintf(filename, "/proc/%d", pid);
207
208 if (flags & PSSCAN_UIDGID) {
209 if (stat(filename, &sb))
210 break;
211
212 sp->uid = sb.st_uid;
213 sp->gid = sb.st_gid;
214 }
215
216 if (flags & PSSCAN_STAT) {
217 char *cp, *comm1;
218 int tty;
219#if !ENABLE_FEATURE_FAST_TOP
220 unsigned long vsz, rss;
221#endif
222
223 strcpy(filename_tail, "/stat");
224 n = read_to_buf(filename, buf);
225 if (n < 0)
226 break;
227 cp = strrchr(buf, ')');
228
229
230 cp[0] = '\0';
231 if (sizeof(sp->comm) < 16)
232 BUG_comm_size();
233 comm1 = strchr(buf, '(');
234
235 safe_strncpy(sp->comm, comm1 + 1, sizeof(sp->comm));
236
237#if !ENABLE_FEATURE_FAST_TOP
238 n = sscanf(cp+2,
239 "%c %u "
240 "%u %u %d %*s "
241 "%*s %*s %*s %*s %*s "
242 "%lu %lu "
243 "%*s %*s %*s "
244 "%ld "
245 "%*s %*s "
246 "%lu "
247 "%lu "
248 "%lu "
249#if ENABLE_FEATURE_TOP_SMP_PROCESS
250 "%*s %*s %*s %*s %*s %*s "
251 "%*s %*s %*s %*s "
252 "%*s %*s %*s %*s "
253 "%d"
254#endif
255 ,
256 sp->state, &sp->ppid,
257 &sp->pgid, &sp->sid, &tty,
258 &sp->utime, &sp->stime,
259 &tasknice,
260 &sp->start_time,
261 &vsz,
262 &rss
263#if ENABLE_FEATURE_TOP_SMP_PROCESS
264 , &sp->last_seen_on_cpu
265#endif
266 );
267
268 if (n < 11)
269 break;
270#if ENABLE_FEATURE_TOP_SMP_PROCESS
271 if (n < 11+15)
272 sp->last_seen_on_cpu = 0;
273#endif
274
275
276 sp->vsz = vsz >> 10;
277
278 sp->rss = rss << sp->shift_pages_to_kb;
279 sp->tty_major = (tty >> 8) & 0xfff;
280 sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00);
281#else
282
283
284 sp->state[0] = cp[2];
285 cp += 4;
286 sp->ppid = fast_strtoul_10(&cp);
287 sp->pgid = fast_strtoul_10(&cp);
288 sp->sid = fast_strtoul_10(&cp);
289 tty = fast_strtoul_10(&cp);
290 sp->tty_major = (tty >> 8) & 0xfff;
291 sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00);
292 cp = skip_fields(cp, 6);
293 sp->utime = fast_strtoul_10(&cp);
294 sp->stime = fast_strtoul_10(&cp);
295 cp = skip_fields(cp, 3);
296 tasknice = fast_strtoul_10(&cp);
297 cp = skip_fields(cp, 2);
298 sp->start_time = fast_strtoul_10(&cp);
299
300 sp->vsz = fast_strtoul_10(&cp) >> 10;
301
302 sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb;
303#if ENABLE_FEATURE_TOP_SMP_PROCESS
304
305
306
307 cp = skip_fields(cp, 14);
308
309 sp->last_seen_on_cpu = fast_strtoul_10(&cp);
310#endif
311#endif
312
313 if (sp->vsz == 0 && sp->state[0] != 'Z')
314 sp->state[1] = 'W';
315 else
316 sp->state[1] = ' ';
317 if (tasknice < 0)
318 sp->state[2] = '<';
319 else if (tasknice)
320 sp->state[2] = 'N';
321 else
322 sp->state[2] = ' ';
323 }
324
325#if ENABLE_FEATURE_TOPMEM
326 if (flags & (PSSCAN_SMAPS)) {
327 FILE *file;
328
329 strcpy(filename_tail, "/smaps");
330 file = fopen_for_read(filename);
331 if (!file)
332 break;
333 while (fgets(buf, sizeof(buf), file)) {
334 unsigned long sz;
335 char *tp;
336 char w;
337#define SCAN(str, name) \
338 if (strncmp(buf, str, sizeof(str)-1) == 0) { \
339 tp = skip_whitespace(buf + sizeof(str)-1); \
340 sp->name += fast_strtoul_10(&tp); \
341 continue; \
342 }
343 SCAN("Shared_Clean:" , shared_clean );
344 SCAN("Shared_Dirty:" , shared_dirty );
345 SCAN("Private_Clean:", private_clean);
346 SCAN("Private_Dirty:", private_dirty);
347#undef SCAN
348
349 tp = strchr(buf, '-');
350 if (tp) {
351 *tp = ' ';
352 tp = buf;
353 sz = fast_strtoul_16(&tp);
354 sz = (fast_strtoul_16(&tp) - sz) >> 10;
355
356 w = tp[1];
357
358 tp = skip_whitespace(skip_fields(tp, 4));
359
360 if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) {
361 if (w == 'w') {
362 sp->mapped_rw += sz;
363 } else if (w == '-') {
364 sp->mapped_ro += sz;
365 }
366 }
367
368 if (strcmp(tp, "[stack]\n") == 0)
369 sp->stack += sz;
370 }
371 }
372 fclose(file);
373 }
374#endif
375
376#if 0
377 if (flags & (PSSCAN_CMD|PSSCAN_ARGV0)) {
378 free(sp->argv0);
379 sp->argv0 = NULL;
380 free(sp->cmd);
381 sp->cmd = NULL;
382 strcpy(filename_tail, "/cmdline");
383
384
385 n = read_to_buf(filename, buf);
386 if (n <= 0)
387 break;
388 if (flags & PSSCAN_ARGV0)
389 sp->argv0 = xstrdup(buf);
390 if (flags & PSSCAN_CMD) {
391 do {
392 n--;
393 if ((unsigned char)(buf[n]) < ' ')
394 buf[n] = ' ';
395 } while (n);
396 sp->cmd = xstrdup(buf);
397 }
398 }
399#else
400 if (flags & (PSSCAN_ARGV0|PSSCAN_ARGVN)) {
401 free(sp->argv0);
402 sp->argv0 = NULL;
403 strcpy(filename_tail, "/cmdline");
404 n = read_to_buf(filename, buf);
405 if (n <= 0)
406 break;
407 if (flags & PSSCAN_ARGVN) {
408 sp->argv_len = n;
409 sp->argv0 = xmalloc(n + 1);
410 memcpy(sp->argv0, buf, n + 1);
411
412 } else {
413 sp->argv_len = 0;
414 sp->argv0 = xstrdup(buf);
415 }
416 }
417#endif
418 break;
419 }
420 return sp;
421}
422
423void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
424{
425 ssize_t sz;
426 char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
427
428 sprintf(filename, "/proc/%u/cmdline", pid);
429 sz = open_read_close(filename, buf, col);
430 if (sz > 0) {
431 buf[sz] = '\0';
432 while (--sz >= 0)
433 if ((unsigned char)(buf[sz]) < ' ')
434 buf[sz] = ' ';
435 } else {
436 snprintf(buf, col, "[%s]", comm);
437 }
438}
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477