Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/libbb/procps.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/libbb/procps.c
r821 r1770 5 5 * Copyright 1998 by Albert Cahalan; all rights reserved. 6 6 * Copyright (C) 2002 by Vladimir Oleynik <dzo@simtreas.ru> 7 * SELinux support: (c) 2007 by Yuichi Nakamura <ynakam@hitachisoft.jp> 7 8 * 8 9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 9 10 */ 10 11 11 #include <dirent.h>12 #include <string.h>13 #include <stdlib.h>14 #include <sys/param.h>15 #include <unistd.h>16 #include <fcntl.h>17 18 12 #include "libbb.h" 19 13 20 14 15 typedef struct unsigned_to_name_map_t { 16 unsigned id; 17 char name[USERNAME_MAX_SIZE]; 18 } unsigned_to_name_map_t; 19 20 typedef struct cache_t { 21 unsigned_to_name_map_t *cache; 22 int size; 23 } cache_t; 24 25 static cache_t username, groupname; 26 27 static void clear_cache(cache_t *cp) 28 { 29 free(cp->cache); 30 cp->cache = NULL; 31 cp->size = 0; 32 } 33 void clear_username_cache(void) 34 { 35 clear_cache(&username); 36 clear_cache(&groupname); 37 } 38 39 #if 0 /* more generic, but we don't need that yet */ 40 /* Returns -N-1 if not found. */ 41 /* cp->cache[N] is allocated and must be filled in this case */ 42 static 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(cp->cache, cp->size * sizeof(*cp->cache)); 50 cp->cache[i++].id = id; 51 return -i; 52 } 53 #endif 54 55 typedef char* ug_func(char *name, int bufsize, long uid); 56 static char* get_cached(cache_t *cp, unsigned id, ug_func* fp) 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(cp->cache, cp->size * sizeof(*cp->cache)); 64 cp->cache[i].id = id; 65 /* Never fails. Generates numeric string if name isn't found */ 66 fp(cp->cache[i].name, sizeof(cp->cache[i].name), id); 67 return cp->cache[i].name; 68 } 69 const char* get_cached_username(uid_t uid) 70 { 71 return get_cached(&username, uid, bb_getpwuid); 72 } 73 const char* get_cached_groupname(gid_t gid) 74 { 75 return get_cached(&groupname, gid, bb_getgrgid); 76 } 77 78 21 79 #define PROCPS_BUFSIZE 1024 22 80 … … 24 82 { 25 83 int fd; 26 ssize_t ret; 27 84 /* open_read_close() would do two reads, checking for EOF. 85 * When you have 10000 /proc/$NUM/stat to read, it isn't desirable */ 86 ssize_t ret = -1; 28 87 fd = open(filename, O_RDONLY); 29 if (fd < 0)30 ret urn -1;31 ret = read(fd, buf, PROCPS_BUFSIZE-1);32 ((char *)buf)[ret > 0 ? ret : 0] = 0;33 close(fd);88 if (fd >= 0) { 89 ret = read(fd, buf, PROCPS_BUFSIZE-1); 90 close(fd); 91 } 92 ((char *)buf)[ret > 0 ? ret : 0] = '\0'; 34 93 return ret; 35 94 } 36 95 37 38 procps_status_t * procps_scan(int save_user_arg0) 39 { 40 static DIR *dir; 96 procps_status_t *alloc_procps_scan(int flags) 97 { 98 procps_status_t* sp = xzalloc(sizeof(procps_status_t)); 99 sp->dir = xopendir("/proc"); 100 return sp; 101 } 102 103 void free_procps_scan(procps_status_t* sp) 104 { 105 closedir(sp->dir); 106 free(sp->argv0); 107 USE_SELINUX(free(sp->context);) 108 free(sp); 109 } 110 111 #if ENABLE_FEATURE_FAST_TOP 112 /* We cut a lot of corners here for speed */ 113 static unsigned long fast_strtoul_10(char **endptr) 114 { 115 char c; 116 char *str = *endptr; 117 unsigned long n = *str - '0'; 118 119 while ((c = *++str) != ' ') 120 n = n*10 + (c - '0'); 121 122 *endptr = str + 1; /* We skip trailing space! */ 123 return n; 124 } 125 static char *skip_fields(char *str, int count) 126 { 127 do { 128 while (*str++ != ' ') 129 continue; 130 /* we found a space char, str points after it */ 131 } while (--count); 132 return str; 133 } 134 #endif 135 136 void BUG_comm_size(void); 137 procps_status_t *procps_scan(procps_status_t* sp, int flags) 138 { 41 139 struct dirent *entry; 42 static procps_status_t ret_status; 43 char *name; 140 char buf[PROCPS_BUFSIZE]; 141 char filename[sizeof("/proc//cmdline") + sizeof(int)*3]; 142 char *filename_tail; 143 long tasknice; 144 unsigned pid; 44 145 int n; 45 char status[32];46 char *status_tail;47 char buf[PROCPS_BUFSIZE];48 procps_status_t curstatus;49 int pid;50 long tasknice;51 146 struct stat sb; 52 147 53 if (!dir) { 54 dir = bb_xopendir("/proc"); 148 if (!sp) 149 sp = alloc_procps_scan(flags); 150 151 for (;;) { 152 entry = readdir(sp->dir); 153 if (entry == NULL) { 154 free_procps_scan(sp); 155 return NULL; 156 } 157 pid = bb_strtou(entry->d_name, NULL, 10); 158 if (errno) 159 continue; 160 161 /* After this point we have to break, not continue 162 * ("continue" would mean that current /proc/NNN 163 * is not a valid process info) */ 164 165 memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz)); 166 167 sp->pid = pid; 168 if (!(flags & ~PSSCAN_PID)) break; 169 170 #if ENABLE_SELINUX 171 if (flags & PSSCAN_CONTEXT) { 172 if (getpidcon(sp->pid, &sp->context) < 0) 173 sp->context = NULL; 174 } 175 #endif 176 177 filename_tail = filename + sprintf(filename, "/proc/%d", pid); 178 179 if (flags & PSSCAN_UIDGID) { 180 if (stat(filename, &sb)) 181 break; 182 /* Need comment - is this effective or real UID/GID? */ 183 sp->uid = sb.st_uid; 184 sp->gid = sb.st_gid; 185 } 186 187 if (flags & PSSCAN_STAT) { 188 char *cp, *comm1; 189 int tty; 190 #if !ENABLE_FEATURE_FAST_TOP 191 unsigned long vsz, rss; 192 #endif 193 194 /* see proc(5) for some details on this */ 195 strcpy(filename_tail, "/stat"); 196 n = read_to_buf(filename, buf); 197 if (n < 0) 198 break; 199 cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */ 200 /*if (!cp || cp[1] != ' ') 201 break;*/ 202 cp[0] = '\0'; 203 if (sizeof(sp->comm) < 16) 204 BUG_comm_size(); 205 comm1 = strchr(buf, '('); 206 /*if (comm1)*/ 207 safe_strncpy(sp->comm, comm1 + 1, sizeof(sp->comm)); 208 209 #if !ENABLE_FEATURE_FAST_TOP 210 n = sscanf(cp+2, 211 "%c %u " /* state, ppid */ 212 "%u %u %d %*s " /* pgid, sid, tty, tpgid */ 213 "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */ 214 "%lu %lu " /* utime, stime */ 215 "%*s %*s %*s " /* cutime, cstime, priority */ 216 "%ld " /* nice */ 217 "%*s %*s %*s " /* timeout, it_real_value, start_time */ 218 "%lu " /* vsize */ 219 "%lu " /* rss */ 220 /* "%lu %lu %lu %lu %lu %lu " rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ 221 /* "%u %u %u %u " signal, blocked, sigignore, sigcatch */ 222 /* "%lu %lu %lu" wchan, nswap, cnswap */ 223 , 224 sp->state, &sp->ppid, 225 &sp->pgid, &sp->sid, &tty, 226 &sp->utime, &sp->stime, 227 &tasknice, 228 &vsz, 229 &rss); 230 if (n != 10) 231 break; 232 sp->vsz = vsz >> 10; /* vsize is in bytes and we want kb */ 233 sp->rss = rss >> 10; 234 sp->tty_major = (tty >> 8) & 0xfff; 235 sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00); 236 #else 237 /* This costs ~100 bytes more but makes top faster by 20% 238 * If you run 10000 processes, this may be important for you */ 239 sp->state[0] = cp[2]; 240 cp += 4; 241 sp->ppid = fast_strtoul_10(&cp); 242 sp->pgid = fast_strtoul_10(&cp); 243 sp->sid = fast_strtoul_10(&cp); 244 tty = fast_strtoul_10(&cp); 245 sp->tty_major = (tty >> 8) & 0xfff; 246 sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00); 247 cp = skip_fields(cp, 6); /* tpgid, flags, min_flt, cmin_flt, maj_flt, cmaj_flt */ 248 sp->utime = fast_strtoul_10(&cp); 249 sp->stime = fast_strtoul_10(&cp); 250 cp = skip_fields(cp, 3); /* cutime, cstime, priority */ 251 tasknice = fast_strtoul_10(&cp); 252 cp = skip_fields(cp, 3); /* timeout, it_real_value, start_time */ 253 sp->vsz = fast_strtoul_10(&cp) >> 10; /* vsize is in bytes and we want kb */ 254 sp->rss = fast_strtoul_10(&cp) >> 10; 255 #endif 256 257 if (sp->vsz == 0 && sp->state[0] != 'Z') 258 sp->state[1] = 'W'; 259 else 260 sp->state[1] = ' '; 261 if (tasknice < 0) 262 sp->state[2] = '<'; 263 else if (tasknice) /* > 0 */ 264 sp->state[2] = 'N'; 265 else 266 sp->state[2] = ' '; 267 268 } 269 270 #if 0 /* PSSCAN_CMD is not used */ 271 if (flags & (PSSCAN_CMD|PSSCAN_ARGV0)) { 272 if (sp->argv0) { 273 free(sp->argv0); 274 sp->argv0 = NULL; 275 } 276 if (sp->cmd) { 277 free(sp->cmd); 278 sp->cmd = NULL; 279 } 280 strcpy(filename_tail, "/cmdline"); 281 /* TODO: to get rid of size limits, read into malloc buf, 282 * then realloc it down to real size. */ 283 n = read_to_buf(filename, buf); 284 if (n <= 0) 285 break; 286 if (flags & PSSCAN_ARGV0) 287 sp->argv0 = xstrdup(buf); 288 if (flags & PSSCAN_CMD) { 289 do { 290 n--; 291 if ((unsigned char)(buf[n]) < ' ') 292 buf[n] = ' '; 293 } while (n); 294 sp->cmd = xstrdup(buf); 295 } 296 } 297 #else 298 if (flags & PSSCAN_ARGV0) { 299 if (sp->argv0) { 300 free(sp->argv0); 301 sp->argv0 = NULL; 302 } 303 strcpy(filename_tail, "/cmdline"); 304 n = read_to_buf(filename, buf); 305 if (n <= 0) 306 break; 307 if (flags & PSSCAN_ARGV0) 308 sp->argv0 = xstrdup(buf); 309 } 310 #endif 311 break; 55 312 } 56 for(;;) { 57 if((entry = readdir(dir)) == NULL) { 58 closedir(dir); 59 dir = 0; 60 return 0; 61 } 62 name = entry->d_name; 63 if (!(*name >= '0' && *name <= '9')) 64 continue; 65 66 memset(&curstatus, 0, sizeof(procps_status_t)); 67 pid = atoi(name); 68 curstatus.pid = pid; 69 70 status_tail = status + sprintf(status, "/proc/%d", pid); 71 if(stat(status, &sb)) 72 continue; 73 bb_getpwuid(curstatus.user, sb.st_uid, sizeof(curstatus.user)); 74 75 /* see proc(5) for some details on this */ 76 strcpy(status_tail, "/stat"); 77 n = read_to_buf(status, buf); 78 if(n < 0) 79 continue; 80 name = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */ 81 if(name == 0 || name[1] != ' ') 82 continue; 83 *name = 0; 84 sscanf(buf, "%*s (%15c", curstatus.short_cmd); 85 n = sscanf(name+2, 86 "%c %d " 87 "%*s %*s %*s %*s " /* pgrp, session, tty, tpgid */ 88 "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */ 89 #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE 90 "%lu %lu " /* utime, stime */ 91 #else 92 "%*s %*s " /* utime, stime */ 93 #endif 94 "%*s %*s %*s " /* cutime, cstime, priority */ 95 "%ld " /* nice */ 96 "%*s %*s %*s " /* timeout, it_real_value, start_time */ 97 "%*s " /* vsize */ 98 "%ld", /* rss */ 99 curstatus.state, &curstatus.ppid, 100 #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE 101 &curstatus.utime, &curstatus.stime, 102 #endif 103 &tasknice, 104 &curstatus.rss); 105 #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE 106 if(n != 6) 107 #else 108 if(n != 4) 109 #endif 110 continue; 111 112 if (curstatus.rss == 0 && curstatus.state[0] != 'Z') 113 curstatus.state[1] = 'W'; 114 else 115 curstatus.state[1] = ' '; 116 if (tasknice < 0) 117 curstatus.state[2] = '<'; 118 else if (tasknice > 0) 119 curstatus.state[2] = 'N'; 120 else 121 curstatus.state[2] = ' '; 122 123 #ifdef PAGE_SHIFT 124 curstatus.rss <<= (PAGE_SHIFT - 10); /* 2**10 = 1kb */ 125 #else 126 curstatus.rss *= (getpagesize() >> 10); /* 2**10 = 1kb */ 127 #endif 128 129 if(save_user_arg0) { 130 strcpy(status_tail, "/cmdline"); 131 n = read_to_buf(status, buf); 132 if(n > 0) { 133 if(buf[n-1]=='\n') 134 buf[--n] = 0; 135 name = buf; 136 while(n) { 137 if(((unsigned char)*name) < ' ') 138 *name = ' '; 139 name++; 140 n--; 141 } 142 *name = 0; 143 if(buf[0]) 144 curstatus.cmd = strdup(buf); 145 /* if NULL it work true also */ 146 } 147 } 148 return memcpy(&ret_status, &curstatus, sizeof(procps_status_t)); 313 return sp; 314 } 315 316 void read_cmdline(char *buf, int col, unsigned pid, const char *comm) 317 { 318 ssize_t sz; 319 char filename[sizeof("/proc//cmdline") + sizeof(int)*3]; 320 321 sprintf(filename, "/proc/%u/cmdline", pid); 322 sz = open_read_close(filename, buf, col); 323 if (sz > 0) { 324 buf[sz] = '\0'; 325 while (--sz >= 0) 326 if ((unsigned char)(buf[sz]) < ' ') 327 buf[sz] = ' '; 328 } else { 329 snprintf(buf, col, "[%s]", comm); 149 330 } 150 331 } 332 333 /* from kernel: 334 // pid comm S ppid pgid sid tty_nr tty_pgrp flg 335 sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ 336 %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ 337 %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n", 338 task->pid, 339 tcomm, 340 state, 341 ppid, 342 pgid, 343 sid, 344 tty_nr, 345 tty_pgrp, 346 task->flags, 347 min_flt, 348 cmin_flt, 349 maj_flt, 350 cmaj_flt, 351 cputime_to_clock_t(utime), 352 cputime_to_clock_t(stime), 353 cputime_to_clock_t(cutime), 354 cputime_to_clock_t(cstime), 355 priority, 356 nice, 357 num_threads, 358 // 0, 359 start_time, 360 vsize, 361 mm ? get_mm_rss(mm) : 0, 362 rsslim, 363 mm ? mm->start_code : 0, 364 mm ? mm->end_code : 0, 365 mm ? mm->start_stack : 0, 366 esp, 367 eip, 368 the rest is some obsolete cruft 369 */
Note:
See TracChangeset
for help on using the changeset viewer.