Annotation of /tags/mkinitrd-6_1_12/busybox/libbb/procps.c
Parent Directory | Revision Log
Revision 532 -
(hide annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
Original Path: trunk/mkinitrd-magellan/busybox/libbb/procps.c
File MIME type: text/plain
File size: 5728 byte(s)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
Original Path: trunk/mkinitrd-magellan/busybox/libbb/procps.c
File MIME type: text/plain
File size: 5728 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
1 | niro | 532 | /* vi: set sw=4 ts=4: */ |
2 | /* | ||
3 | * Utility routines. | ||
4 | * | ||
5 | * Copyright 1998 by Albert Cahalan; all rights reserved. | ||
6 | * Copyright (C) 2002 by Vladimir Oleynik <dzo@simtreas.ru> | ||
7 | * | ||
8 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
9 | */ | ||
10 | |||
11 | #include "libbb.h" | ||
12 | |||
13 | |||
14 | typedef struct unsigned_to_name_map_t { | ||
15 | unsigned id; | ||
16 | char name[USERNAME_MAX_SIZE]; | ||
17 | } unsigned_to_name_map_t; | ||
18 | |||
19 | typedef struct cache_t { | ||
20 | unsigned_to_name_map_t *cache; | ||
21 | int size; | ||
22 | } cache_t; | ||
23 | |||
24 | static cache_t username, groupname; | ||
25 | |||
26 | static void clear_cache(cache_t *cp) | ||
27 | { | ||
28 | free(cp->cache); | ||
29 | cp->cache = NULL; | ||
30 | cp->size = 0; | ||
31 | } | ||
32 | void clear_username_cache(void) | ||
33 | { | ||
34 | clear_cache(&username); | ||
35 | clear_cache(&groupname); | ||
36 | } | ||
37 | |||
38 | #if 0 /* more generic, but we don't need that yet */ | ||
39 | /* Returns -N-1 if not found. */ | ||
40 | /* cp->cache[N] is allocated and must be filled in this case */ | ||
41 | static int get_cached(cache_t *cp, unsigned id) | ||
42 | { | ||
43 | int i; | ||
44 | for (i = 0; i < cp->size; i++) | ||
45 | if (cp->cache[i].id == id) | ||
46 | return i; | ||
47 | i = cp->size++; | ||
48 | cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache)); | ||
49 | cp->cache[i++].id = id; | ||
50 | return -i; | ||
51 | } | ||
52 | #endif | ||
53 | |||
54 | typedef char* ug_func(char *name, long uid, int bufsize); | ||
55 | static char* get_cached(cache_t *cp, unsigned id, ug_func* fp) | ||
56 | { | ||
57 | int i; | ||
58 | for (i = 0; i < cp->size; i++) | ||
59 | if (cp->cache[i].id == id) | ||
60 | return cp->cache[i].name; | ||
61 | i = cp->size++; | ||
62 | cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache)); | ||
63 | cp->cache[i].id = id; | ||
64 | fp(cp->cache[i].name, id, sizeof(cp->cache[i].name)); | ||
65 | return cp->cache[i].name; | ||
66 | } | ||
67 | const char* get_cached_username(uid_t uid) | ||
68 | { | ||
69 | return get_cached(&username, uid, bb_getpwuid); | ||
70 | } | ||
71 | const char* get_cached_groupname(gid_t gid) | ||
72 | { | ||
73 | return get_cached(&groupname, gid, bb_getgrgid); | ||
74 | } | ||
75 | |||
76 | |||
77 | #define PROCPS_BUFSIZE 1024 | ||
78 | |||
79 | static int read_to_buf(const char *filename, void *buf) | ||
80 | { | ||
81 | ssize_t ret; | ||
82 | ret = open_read_close(filename, buf, PROCPS_BUFSIZE-1); | ||
83 | ((char *)buf)[ret > 0 ? ret : 0] = '\0'; | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | procps_status_t* alloc_procps_scan(int flags) | ||
88 | { | ||
89 | procps_status_t* sp = xzalloc(sizeof(procps_status_t)); | ||
90 | sp->dir = xopendir("/proc"); | ||
91 | return sp; | ||
92 | } | ||
93 | |||
94 | void free_procps_scan(procps_status_t* sp) | ||
95 | { | ||
96 | closedir(sp->dir); | ||
97 | free(sp->cmd); | ||
98 | free(sp); | ||
99 | } | ||
100 | |||
101 | void BUG_comm_size(void); | ||
102 | procps_status_t* procps_scan(procps_status_t* sp, int flags) | ||
103 | { | ||
104 | struct dirent *entry; | ||
105 | char buf[PROCPS_BUFSIZE]; | ||
106 | char filename[sizeof("/proc//cmdline") + sizeof(int)*3]; | ||
107 | char *filename_tail; | ||
108 | long tasknice; | ||
109 | unsigned pid; | ||
110 | int n; | ||
111 | struct stat sb; | ||
112 | |||
113 | if (!sp) | ||
114 | sp = alloc_procps_scan(flags); | ||
115 | |||
116 | for (;;) { | ||
117 | entry = readdir(sp->dir); | ||
118 | if (entry == NULL) { | ||
119 | free_procps_scan(sp); | ||
120 | return NULL; | ||
121 | } | ||
122 | pid = bb_strtou(entry->d_name, NULL, 10); | ||
123 | if (errno) | ||
124 | continue; | ||
125 | |||
126 | /* After this point we have to break, not continue | ||
127 | * ("continue" would mean that current /proc/NNN | ||
128 | * is not a valid process info) */ | ||
129 | |||
130 | memset(&sp->rss, 0, sizeof(*sp) - offsetof(procps_status_t, rss)); | ||
131 | |||
132 | sp->pid = pid; | ||
133 | if (!(flags & ~PSSCAN_PID)) break; | ||
134 | |||
135 | filename_tail = filename + sprintf(filename, "/proc/%d", pid); | ||
136 | |||
137 | if (flags & PSSCAN_UIDGID) { | ||
138 | if (stat(filename, &sb)) | ||
139 | break; | ||
140 | /* Need comment - is this effective or real UID/GID? */ | ||
141 | sp->uid = sb.st_uid; | ||
142 | sp->gid = sb.st_gid; | ||
143 | } | ||
144 | |||
145 | if (flags & PSSCAN_STAT) { | ||
146 | char *cp; | ||
147 | /* see proc(5) for some details on this */ | ||
148 | strcpy(filename_tail, "/stat"); | ||
149 | n = read_to_buf(filename, buf); | ||
150 | if (n < 0) | ||
151 | break; | ||
152 | cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */ | ||
153 | if (!cp || cp[1] != ' ') | ||
154 | break; | ||
155 | cp[0] = '\0'; | ||
156 | if (sizeof(sp->comm) < 16) | ||
157 | BUG_comm_size(); | ||
158 | sscanf(buf, "%*s (%15c", sp->comm); | ||
159 | n = sscanf(cp+2, | ||
160 | "%c %u " /* state, ppid */ | ||
161 | "%u %u %*s %*s " /* pgid, sid, tty, tpgid */ | ||
162 | "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */ | ||
163 | "%lu %lu " /* utime, stime */ | ||
164 | "%*s %*s %*s " /* cutime, cstime, priority */ | ||
165 | "%ld " /* nice */ | ||
166 | "%*s %*s %*s " /* timeout, it_real_value, start_time */ | ||
167 | "%*s " /* vsize */ | ||
168 | "%lu", /* rss */ | ||
169 | sp->state, &sp->ppid, | ||
170 | &sp->pgid, &sp->sid, | ||
171 | &sp->utime, &sp->stime, | ||
172 | &tasknice, | ||
173 | &sp->rss); | ||
174 | if (n != 8) | ||
175 | break; | ||
176 | |||
177 | if (sp->rss == 0 && sp->state[0] != 'Z') | ||
178 | sp->state[1] = 'W'; | ||
179 | else | ||
180 | sp->state[1] = ' '; | ||
181 | if (tasknice < 0) | ||
182 | sp->state[2] = '<'; | ||
183 | else if (tasknice > 0) | ||
184 | sp->state[2] = 'N'; | ||
185 | else | ||
186 | sp->state[2] = ' '; | ||
187 | |||
188 | #ifdef PAGE_SHIFT | ||
189 | sp->rss <<= (PAGE_SHIFT - 10); /* 2**10 = 1kb */ | ||
190 | #else | ||
191 | sp->rss *= (getpagesize() >> 10); /* 2**10 = 1kb */ | ||
192 | #endif | ||
193 | } | ||
194 | |||
195 | if (flags & PSSCAN_CMD) { | ||
196 | free(sp->cmd); | ||
197 | sp->cmd = NULL; | ||
198 | strcpy(filename_tail, "/cmdline"); | ||
199 | n = read_to_buf(filename, buf); | ||
200 | if (n <= 0) | ||
201 | break; | ||
202 | if (buf[n-1] == '\n') { | ||
203 | if (!--n) | ||
204 | break; | ||
205 | buf[n] = '\0'; | ||
206 | } | ||
207 | do { | ||
208 | n--; | ||
209 | if ((unsigned char)(buf[n]) < ' ') | ||
210 | buf[n] = ' '; | ||
211 | } while (n); | ||
212 | sp->cmd = xstrdup(buf); | ||
213 | } | ||
214 | break; | ||
215 | } | ||
216 | return sp; | ||
217 | } | ||
218 | /* from kernel: | ||
219 | // pid comm S ppid pgid sid tty_nr tty_pgrp flg | ||
220 | sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ | ||
221 | %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ | ||
222 | %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n", | ||
223 | task->pid, | ||
224 | tcomm, | ||
225 | state, | ||
226 | ppid, | ||
227 | pgid, | ||
228 | sid, | ||
229 | tty_nr, | ||
230 | tty_pgrp, | ||
231 | task->flags, | ||
232 | min_flt, | ||
233 | |||
234 | cmin_flt, | ||
235 | maj_flt, | ||
236 | cmaj_flt, | ||
237 | cputime_to_clock_t(utime), | ||
238 | cputime_to_clock_t(stime), | ||
239 | cputime_to_clock_t(cutime), | ||
240 | cputime_to_clock_t(cstime), | ||
241 | priority, | ||
242 | nice, | ||
243 | num_threads, | ||
244 | // 0, | ||
245 | start_time, | ||
246 | vsize, | ||
247 | mm ? get_mm_rss(mm) : 0, | ||
248 | rsslim, | ||
249 | mm ? mm->start_code : 0, | ||
250 | mm ? mm->end_code : 0, | ||
251 | mm ? mm->start_stack : 0, | ||
252 | esp, | ||
253 | eip, | ||
254 | the rest is some obsolete cruft | ||
255 | */ |