aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2006-11-05 00:43:51 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2006-11-05 00:43:51 +0000
commit48b1ebd12ec4ef182b4ea423f2309705ae141e8e (patch)
tree5deb7d2b82c280440761cceb4281738867d5631a /libbb
parentd2c185589694b83e492144a6a5d0f79e16dd9b74 (diff)
downloadbusybox-w32-48b1ebd12ec4ef182b4ea423f2309705ae141e8e.tar.gz
busybox-w32-48b1ebd12ec4ef182b4ea423f2309705ae141e8e.tar.bz2
busybox-w32-48b1ebd12ec4ef182b4ea423f2309705ae141e8e.zip
replace /proc scanning code by more versatile one.
Use it where appropriate. Stop scanning /etc/passwd *for every process*!!! (uid->username) top: reduce memory usage - we won't save unneeded fields from /proc info anymore. Downside: ~+250 bytes of code git-svn-id: svn://busybox.net/trunk/busybox@16509 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'libbb')
-rw-r--r--libbb/find_pid_by_name.c6
-rw-r--r--libbb/procps.c261
2 files changed, 174 insertions, 93 deletions
diff --git a/libbb/find_pid_by_name.c b/libbb/find_pid_by_name.c
index 05f7f968f..e98616940 100644
--- a/libbb/find_pid_by_name.c
+++ b/libbb/find_pid_by_name.c
@@ -23,11 +23,11 @@ pid_t* find_pid_by_name(const char* procName)
23{ 23{
24 pid_t* pidList; 24 pid_t* pidList;
25 int i = 0; 25 int i = 0;
26 procps_status_t* p; 26 procps_status_t* p = NULL;
27 27
28 pidList = xmalloc(sizeof(*pidList)); 28 pidList = xmalloc(sizeof(*pidList));
29 while ((p = procps_scan(0)) != 0) { 29 while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM))) {
30 if (strncmp(p->short_cmd, procName, COMM_LEN-1) == 0) { 30 if (strncmp(p->comm, procName, sizeof(p->comm)-1) == 0) {
31 pidList = xrealloc(pidList, sizeof(*pidList) * (i+2)); 31 pidList = xrealloc(pidList, sizeof(*pidList) * (i+2));
32 pidList[i++] = p->pid; 32 pidList[i++] = p->pid;
33 } 33 }
diff --git a/libbb/procps.c b/libbb/procps.c
index 15f77153a..dee5638e4 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -11,6 +11,35 @@
11#include "libbb.h" 11#include "libbb.h"
12 12
13 13
14typedef struct {
15 uid_t uid;
16 char username[12];
17} user_map_t;
18
19static user_map_t *username_cache;
20static int username_cache_size;
21
22void clear_username_cache(void)
23{
24 free(username_cache);
25 username_cache = NULL;
26 username_cache_size = 0;
27}
28
29const char* get_cached_username(uid_t uid)
30{
31 int i;
32 for (i = 0; i < username_cache_size; i++)
33 if (username_cache[i].uid == uid)
34 return username_cache[i].username;
35 i = username_cache_size++;
36 username_cache = xrealloc(username_cache, username_cache_size * sizeof(*username_cache));
37 username_cache[i].uid = uid;
38 bb_getpwuid(username_cache[i].username, uid, sizeof(username_cache[i].username));
39 return username_cache[i].username;
40}
41
42
14#define PROCPS_BUFSIZE 1024 43#define PROCPS_BUFSIZE 1024
15 44
16static int read_to_buf(const char *filename, void *buf) 45static int read_to_buf(const char *filename, void *buf)
@@ -21,119 +50,171 @@ static int read_to_buf(const char *filename, void *buf)
21 return ret; 50 return ret;
22} 51}
23 52
53procps_status_t* alloc_procps_scan(int flags)
54{
55 procps_status_t* sp = xzalloc(sizeof(procps_status_t));
56 sp->dir = xopendir("/proc");
57 return sp;
58}
24 59
25procps_status_t * procps_scan(int save_user_arg0) 60void free_procps_scan(procps_status_t* sp)
26{ 61{
27 static DIR *dir; 62 closedir(sp->dir);
28 static procps_status_t ret_status; 63 free(sp->cmd);
64 free(sp);
65}
29 66
67void BUG_comm_size(void);
68procps_status_t* procps_scan(procps_status_t* sp, int flags)
69{
30 struct dirent *entry; 70 struct dirent *entry;
31 char *name;
32 char buf[PROCPS_BUFSIZE]; 71 char buf[PROCPS_BUFSIZE];
33 char status[sizeof("/proc//cmdline") + sizeof(int)*3]; 72 char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
34 char *status_tail; 73 char *filename_tail;
35 procps_status_t curstatus;
36 long tasknice; 74 long tasknice;
37 int pid; 75 unsigned pid;
38 int n; 76 int n;
39 struct stat sb; 77 struct stat sb;
40 78
41 if (!dir) { 79 if (!sp)
42 dir = xopendir("/proc"); 80 sp = alloc_procps_scan(flags);
43 } 81
44 for (;;) { 82 for (;;) {
45 entry = readdir(dir); 83 entry = readdir(sp->dir);
46 if (entry == NULL) { 84 if (entry == NULL) {
47 closedir(dir); 85 free_procps_scan(sp);
48 dir = 0; 86 return NULL;
49 return 0;
50 } 87 }
51 name = entry->d_name; 88 if (safe_strtou(entry->d_name, &pid))
52 if (!(*name >= '0' && *name <= '9'))
53 continue; 89 continue;
54 90
55 memset(&curstatus, 0, sizeof(procps_status_t)); 91 /* After this point we have to break, not continue
56 pid = atoi(name); 92 * ("continue" would mean that current /proc/NNN
57 curstatus.pid = pid; 93 * is not a valid process info) */
58 94
59 status_tail = status + sprintf(status, "/proc/%d", pid); 95 memset(&sp->rss, 0, sizeof(*sp) - offsetof(procps_status_t, rss));
60 if (stat(status, &sb))
61 continue;
62 bb_getpwuid(curstatus.user, sb.st_uid, sizeof(curstatus.user));
63 96
64 /* see proc(5) for some details on this */ 97 sp->pid = pid;
65 strcpy(status_tail, "/stat"); 98 if (!(flags & ~PSSCAN_PID)) break;
66 n = read_to_buf(status, buf);
67 if (n < 0)
68 continue;
69 name = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
70 if (name == 0 || name[1] != ' ')
71 continue;
72 *name = 0;
73 sscanf(buf, "%*s (%15c", curstatus.short_cmd);
74 n = sscanf(name+2,
75 "%c %d "
76 "%*s %*s %*s %*s " /* pgrp, session, tty, tpgid */
77 "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
78#ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
79 "%lu %lu " /* utime, stime */
80#else
81 "%*s %*s " /* utime, stime */
82#endif
83 "%*s %*s %*s " /* cutime, cstime, priority */
84 "%ld " /* nice */
85 "%*s %*s %*s " /* timeout, it_real_value, start_time */
86 "%*s " /* vsize */
87 "%ld", /* rss */
88 curstatus.state, &curstatus.ppid,
89#ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
90 &curstatus.utime, &curstatus.stime,
91#endif
92 &tasknice,
93 &curstatus.rss);
94#ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
95 if (n != 6)
96#else
97 if (n != 4)
98#endif
99 continue;
100 99
101 if (curstatus.rss == 0 && curstatus.state[0] != 'Z') 100 filename_tail = filename + sprintf(filename, "/proc/%d", pid);
102 curstatus.state[1] = 'W'; 101
103 else 102 if (flags & PSSCAN_UIDGID) {
104 curstatus.state[1] = ' '; 103 if (stat(filename, &sb))
105 if (tasknice < 0) 104 break;
106 curstatus.state[2] = '<'; 105 /* Need comment - is this effective or read UID/GID? */
107 else if (tasknice > 0) 106 sp->uid = sb.st_uid;
108 curstatus.state[2] = 'N'; 107 sp->gid = sb.st_gid;
109 else 108 }
110 curstatus.state[2] = ' '; 109
110 if (flags & PSSCAN_STAT) {
111 char *cp;
112 /* see proc(5) for some details on this */
113 strcpy(filename_tail, "/stat");
114 n = read_to_buf(filename, buf);
115 if (n < 0)
116 break;
117 cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
118 if (!cp || cp[1] != ' ')
119 break;
120 cp[0] = '\0';
121 if (sizeof(sp->comm) < 16)
122 BUG_comm_size();
123 sscanf(buf, "%*s (%15c", sp->comm);
124 n = sscanf(cp+2,
125 "%c %u " /* state, ppid */
126 "%u %u %*s %*s " /* pgid, sid, tty, tpgid */
127 "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
128 "%lu %lu " /* utime, stime */
129 "%*s %*s %*s " /* cutime, cstime, priority */
130 "%ld " /* nice */
131 "%*s %*s %*s " /* timeout, it_real_value, start_time */
132 "%*s " /* vsize */
133 "%lu", /* rss */
134 sp->state, &sp->ppid,
135 &sp->pgid, &sp->sid,
136 &sp->utime, &sp->stime,
137 &tasknice,
138 &sp->rss);
139 if (n != 8)
140 break;
141
142 if (sp->rss == 0 && sp->state[0] != 'Z')
143 sp->state[1] = 'W';
144 else
145 sp->state[1] = ' ';
146 if (tasknice < 0)
147 sp->state[2] = '<';
148 else if (tasknice > 0)
149 sp->state[2] = 'N';
150 else
151 sp->state[2] = ' ';
111 152
112#ifdef PAGE_SHIFT 153#ifdef PAGE_SHIFT
113 curstatus.rss <<= (PAGE_SHIFT - 10); /* 2**10 = 1kb */ 154 sp->rss <<= (PAGE_SHIFT - 10); /* 2**10 = 1kb */
114#else 155#else
115 curstatus.rss *= (getpagesize() >> 10); /* 2**10 = 1kb */ 156 sp->rss *= (getpagesize() >> 10); /* 2**10 = 1kb */
116#endif 157#endif
158 }
117 159
118 if (save_user_arg0) { 160 if (flags & PSSCAN_CMD) {
119 strcpy(status_tail, "/cmdline"); 161 free(sp->cmd);
120 n = read_to_buf(status, buf); 162 sp->cmd = NULL;
121 if (n > 0) { 163 strcpy(filename_tail, "/cmdline");
122 if (buf[n-1]=='\n') 164 n = read_to_buf(filename, buf);
123 buf[--n] = 0; 165 if (n <= 0)
124 name = buf; 166 break;
125 while (n) { 167 if (buf[n-1] == '\n') {
126 if (((unsigned char)*name) < ' ') 168 if (!--n)
127 *name = ' '; 169 break;
128 name++; 170 buf[n] = '\0';
129 n--;
130 }
131 *name = 0;
132 if (buf[0])
133 curstatus.cmd = strdup(buf);
134 /* if NULL it work true also */
135 } 171 }
172 do {
173 n--;
174 if ((unsigned char)(buf[n]) < ' ')
175 buf[n] = ' ';
176 } while (n);
177 sp->cmd = strdup(buf);
136 } 178 }
137 return memcpy(&ret_status, &curstatus, sizeof(procps_status_t)); 179 break;
138 } 180 }
181 return sp;
139} 182}
183/* from kernel:
184 // pid comm S ppid pgid sid tty_nr tty_pgrp flg
185 sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
186%lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
187%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n",
188 task->pid,
189 tcomm,
190 state,
191 ppid,
192 pgid,
193 sid,
194 tty_nr,
195 tty_pgrp,
196 task->flags,
197 min_flt,
198
199 cmin_flt,
200 maj_flt,
201 cmaj_flt,
202 cputime_to_clock_t(utime),
203 cputime_to_clock_t(stime),
204 cputime_to_clock_t(cutime),
205 cputime_to_clock_t(cstime),
206 priority,
207 nice,
208 num_threads,
209 // 0,
210 start_time,
211 vsize,
212 mm ? get_mm_rss(mm) : 0,
213 rsslim,
214 mm ? mm->start_code : 0,
215 mm ? mm->end_code : 0,
216 mm ? mm->start_stack : 0,
217 esp,
218 eip,
219the rest is some obsolete cruft
220*/