diff options
author | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2006-11-05 00:43:51 +0000 |
---|---|---|
committer | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2006-11-05 00:43:51 +0000 |
commit | 48b1ebd12ec4ef182b4ea423f2309705ae141e8e (patch) | |
tree | 5deb7d2b82c280440761cceb4281738867d5631a /libbb | |
parent | d2c185589694b83e492144a6a5d0f79e16dd9b74 (diff) | |
download | busybox-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.c | 6 | ||||
-rw-r--r-- | libbb/procps.c | 261 |
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 | ||
14 | typedef struct { | ||
15 | uid_t uid; | ||
16 | char username[12]; | ||
17 | } user_map_t; | ||
18 | |||
19 | static user_map_t *username_cache; | ||
20 | static int username_cache_size; | ||
21 | |||
22 | void clear_username_cache(void) | ||
23 | { | ||
24 | free(username_cache); | ||
25 | username_cache = NULL; | ||
26 | username_cache_size = 0; | ||
27 | } | ||
28 | |||
29 | const 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 | ||
16 | static int read_to_buf(const char *filename, void *buf) | 45 | static 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 | ||
53 | procps_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 | ||
25 | procps_status_t * procps_scan(int save_user_arg0) | 60 | void 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 | ||
67 | void BUG_comm_size(void); | ||
68 | procps_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, | ||
219 | the rest is some obsolete cruft | ||
220 | */ | ||