Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/libbb/procps.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/libbb/procps.c
r1765 r2725 7 7 * SELinux support: (c) 2007 by Yuichi Nakamura <ynakam@hitachisoft.jp> 8 8 * 9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.9 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 10 10 */ 11 11 … … 14 14 15 15 typedef struct unsigned_to_name_map_t { 16 unsignedid;16 long id; 17 17 char name[USERNAME_MAX_SIZE]; 18 18 } unsigned_to_name_map_t; … … 31 31 cp->size = 0; 32 32 } 33 void clear_username_cache(void)33 void FAST_FUNC clear_username_cache(void) 34 34 { 35 35 clear_cache(&username); … … 47 47 return i; 48 48 i = cp->size++; 49 cp->cache = xrealloc (cp->cache, cp->size * sizeof(*cp->cache));49 cp->cache = xrealloc_vector(cp->cache, 2, i); 50 50 cp->cache[i++].id = id; 51 51 return -i; … … 53 53 #endif 54 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)55 static char* get_cached(cache_t *cp, long id, 56 char* FAST_FUNC x2x_utoa(long id)) 57 57 { 58 58 int i; … … 61 61 return cp->cache[i].name; 62 62 i = cp->size++; 63 cp->cache = xrealloc (cp->cache, cp->size * sizeof(*cp->cache));63 cp->cache = xrealloc_vector(cp->cache, 2, i); 64 64 cp->cache[i].id = id; 65 65 /* Never fails. Generates numeric string if name isn't found */ 66 fp(cp->cache[i].name, sizeof(cp->cache[i].name), id);66 safe_strncpy(cp->cache[i].name, x2x_utoa(id), sizeof(cp->cache[i].name)); 67 67 return cp->cache[i].name; 68 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);69 const char* FAST_FUNC get_cached_username(uid_t uid) 70 { 71 return get_cached(&username, uid, uid2uname_utoa); 72 } 73 const char* FAST_FUNC get_cached_groupname(gid_t gid) 74 { 75 return get_cached(&groupname, gid, gid2group_utoa); 76 76 } 77 77 … … 94 94 } 95 95 96 procps_status_t *alloc_procps_scan(int flags) 97 { 96 static procps_status_t* FAST_FUNC alloc_procps_scan(void) 97 { 98 unsigned n = getpagesize(); 98 99 procps_status_t* sp = xzalloc(sizeof(procps_status_t)); 99 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; 100 107 return sp; 101 108 } 102 109 103 void free_procps_scan(procps_status_t* sp)110 void FAST_FUNC free_procps_scan(procps_status_t* sp) 104 111 { 105 112 closedir(sp->dir); 113 #if ENABLE_FEATURE_SHOW_THREADS 114 if (sp->task_dir) 115 closedir(sp->task_dir); 116 #endif 106 117 free(sp->argv0); 107 USE_SELINUX(free(sp->context);) 118 free(sp->exe); 119 IF_SELINUX(free(sp->context);) 108 120 free(sp); 109 121 } 110 122 111 #if ENABLE_FEATURE_FAST_TOP 123 #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP 124 static unsigned long fast_strtoul_16(char **endptr) 125 { 126 unsigned char c; 127 char *str = *endptr; 128 unsigned long n = 0; 129 130 while ((c = *str++) != ' ') { 131 c = ((c|0x20) - '0'); 132 if (c > 9) 133 // c = c + '0' - 'a' + 10: 134 c = c - ('a' - '0' - 10); 135 n = n*16 + c; 136 } 137 *endptr = str; /* We skip trailing space! */ 138 return n; 139 } 140 #endif 141 142 #if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP 112 143 /* We cut a lot of corners here for speed */ 113 144 static unsigned long fast_strtoul_10(char **endptr) … … 123 154 return n; 124 155 } 156 157 # if ENABLE_FEATURE_FAST_TOP 158 static long fast_strtol_10(char **endptr) 159 { 160 if (**endptr != '-') 161 return fast_strtoul_10(endptr); 162 163 (*endptr)++; 164 return - (long)fast_strtoul_10(endptr); 165 } 166 # endif 167 125 168 static char *skip_fields(char *str, int count) 126 169 { … … 134 177 #endif 135 178 179 #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP 180 int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, 181 void (*cb)(struct smaprec *, void *), void *data) 182 { 183 FILE *file; 184 struct smaprec currec; 185 char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; 186 char buf[PROCPS_BUFSIZE]; 187 #if !ENABLE_PMAP 188 void (*cb)(struct smaprec *, void *) = NULL; 189 void *data = NULL; 190 #endif 191 192 sprintf(filename, "/proc/%u/smaps", (int)pid); 193 194 file = fopen_for_read(filename); 195 if (!file) 196 return 1; 197 198 memset(&currec, 0, sizeof(currec)); 199 while (fgets(buf, PROCPS_BUFSIZE, file)) { 200 // Each mapping datum has this form: 201 // f7d29000-f7d39000 rw-s ADR M:m OFS FILE 202 // Size: nnn kB 203 // Rss: nnn kB 204 // ..... 205 206 char *tp = buf, *p; 207 208 #define SCAN(S, X) \ 209 if (strncmp(tp, S, sizeof(S)-1) == 0) { \ 210 tp = skip_whitespace(tp + sizeof(S)-1); \ 211 total->X += currec.X = fast_strtoul_10(&tp); \ 212 continue; \ 213 } 214 if (cb) { 215 SCAN("Pss:" , smap_pss ); 216 SCAN("Swap:" , smap_swap ); 217 } 218 SCAN("Private_Dirty:", private_dirty); 219 SCAN("Private_Clean:", private_clean); 220 SCAN("Shared_Dirty:" , shared_dirty ); 221 SCAN("Shared_Clean:" , shared_clean ); 222 #undef SCAN 223 tp = strchr(buf, '-'); 224 if (tp) { 225 // We reached next mapping - the line of this form: 226 // f7d29000-f7d39000 rw-s ADR M:m OFS FILE 227 228 if (cb) { 229 /* If we have a previous record, there's nothing more 230 * for it, call the callback and clear currec 231 */ 232 if (currec.smap_size) 233 cb(&currec, data); 234 free(currec.smap_name); 235 } 236 memset(&currec, 0, sizeof(currec)); 237 238 *tp = ' '; 239 tp = buf; 240 currec.smap_start = fast_strtoul_16(&tp); 241 currec.smap_size = (fast_strtoul_16(&tp) - currec.smap_start) >> 10; 242 243 strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1); 244 245 // skipping "rw-s ADR M:m OFS " 246 tp = skip_whitespace(skip_fields(tp, 4)); 247 // filter out /dev/something (something != zero) 248 if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) { 249 if (currec.smap_mode[1] == 'w') { 250 currec.mapped_rw = currec.smap_size; 251 total->mapped_rw += currec.smap_size; 252 } else if (currec.smap_mode[1] == '-') { 253 currec.mapped_ro = currec.smap_size; 254 total->mapped_ro += currec.smap_size; 255 } 256 } 257 258 if (strcmp(tp, "[stack]\n") == 0) 259 total->stack += currec.smap_size; 260 if (cb) { 261 p = skip_non_whitespace(tp); 262 if (p == tp) { 263 currec.smap_name = xstrdup(" [ anon ]"); 264 } else { 265 *p = '\0'; 266 currec.smap_name = xstrdup(tp); 267 } 268 } 269 total->smap_size += currec.smap_size; 270 } 271 } 272 fclose(file); 273 274 if (cb) { 275 if (currec.smap_size) 276 cb(&currec, data); 277 free(currec.smap_name); 278 } 279 280 return 0; 281 } 282 #endif 283 136 284 void BUG_comm_size(void); 137 procps_status_t *procps_scan(procps_status_t* sp, int flags)285 procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) 138 286 { 139 287 struct dirent *entry; … … 147 295 148 296 if (!sp) 149 sp = alloc_procps_scan( flags);297 sp = alloc_procps_scan(); 150 298 151 299 for (;;) { 300 #if ENABLE_FEATURE_SHOW_THREADS 301 if ((flags & PSSCAN_TASKS) && sp->task_dir) { 302 entry = readdir(sp->task_dir); 303 if (entry) 304 goto got_entry; 305 closedir(sp->task_dir); 306 sp->task_dir = NULL; 307 } 308 #endif 152 309 entry = readdir(sp->dir); 153 310 if (entry == NULL) { … … 155 312 return NULL; 156 313 } 314 IF_FEATURE_SHOW_THREADS(got_entry:) 157 315 pid = bb_strtou(entry->d_name, NULL, 10); 158 316 if (errno) 159 317 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) */ 318 #if ENABLE_FEATURE_SHOW_THREADS 319 if ((flags & PSSCAN_TASKS) && !sp->task_dir) { 320 /* We found another /proc/PID. Do not use it, 321 * there will be /proc/PID/task/PID (same PID!), 322 * so just go ahead and dive into /proc/PID/task. */ 323 char task_dir[sizeof("/proc/%u/task") + sizeof(int)*3]; 324 sprintf(task_dir, "/proc/%u/task", pid); 325 sp->task_dir = xopendir(task_dir); 326 continue; 327 } 328 #endif 329 330 /* After this point we can: 331 * "break": stop parsing, return the data 332 * "continue": try next /proc/XXX 333 */ 164 334 165 335 memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz)); 166 336 167 337 sp->pid = pid; 168 if (!(flags & ~PSSCAN_PID)) break; 338 if (!(flags & ~PSSCAN_PID)) 339 break; /* we needed only pid, we got it */ 169 340 170 341 #if ENABLE_SELINUX … … 175 346 #endif 176 347 177 filename_tail = filename + sprintf(filename, "/proc/% d", pid);348 filename_tail = filename + sprintf(filename, "/proc/%u/", pid); 178 349 179 350 if (flags & PSSCAN_UIDGID) { 180 351 if (stat(filename, &sb)) 181 break;182 /* Need comment - is this effective or real UID/GID?*/352 continue; /* process probably exited */ 353 /* Effective UID/GID, not real */ 183 354 sp->uid = sb.st_uid; 184 355 sp->gid = sb.st_gid; … … 191 362 unsigned long vsz, rss; 192 363 #endif 193 194 364 /* see proc(5) for some details on this */ 195 strcpy(filename_tail, " /stat");365 strcpy(filename_tail, "stat"); 196 366 n = read_to_buf(filename, buf); 197 367 if (n < 0) 198 break;368 continue; /* process probably exited */ 199 369 cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */ 200 370 /*if (!cp || cp[1] != ' ') 201 break;*/371 continue;*/ 202 372 cp[0] = '\0'; 203 373 if (sizeof(sp->comm) < 16) … … 215 385 "%*s %*s %*s " /* cutime, cstime, priority */ 216 386 "%ld " /* nice */ 217 "%*s %*s %*s " /* timeout, it_real_value, start_time */ 387 "%*s %*s " /* timeout, it_real_value */ 388 "%lu " /* start_time */ 218 389 "%lu " /* vsize */ 219 390 "%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 */ 391 # if ENABLE_FEATURE_TOP_SMP_PROCESS 392 "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ 393 "%*s %*s %*s %*s " /*signal, blocked, sigignore, sigcatch */ 394 "%*s %*s %*s %*s " /*wchan, nswap, cnswap, exit_signal */ 395 "%d" /*cpu last seen on*/ 396 # endif 223 397 , 224 398 sp->state, &sp->ppid, … … 226 400 &sp->utime, &sp->stime, 227 401 &tasknice, 402 &sp->start_time, 228 403 &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; 404 &rss 405 # if ENABLE_FEATURE_TOP_SMP_PROCESS 406 , &sp->last_seen_on_cpu 407 # endif 408 ); 409 410 if (n < 11) 411 continue; /* bogus data, get next /proc/XXX */ 412 # if ENABLE_FEATURE_TOP_SMP_PROCESS 413 if (n < 11+15) 414 sp->last_seen_on_cpu = 0; 415 # endif 416 417 /* vsz is in bytes and we want kb */ 418 sp->vsz = vsz >> 10; 419 /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ 420 sp->rss = rss << sp->shift_pages_to_kb; 234 421 sp->tty_major = (tty >> 8) & 0xfff; 235 422 sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00); … … 249 436 sp->stime = fast_strtoul_10(&cp); 250 437 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; 438 tasknice = fast_strtol_10(&cp); 439 cp = skip_fields(cp, 2); /* timeout, it_real_value */ 440 sp->start_time = fast_strtoul_10(&cp); 441 /* vsz is in bytes and we want kb */ 442 sp->vsz = fast_strtoul_10(&cp) >> 10; 443 /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ 444 sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; 445 # if ENABLE_FEATURE_TOP_SMP_PROCESS 446 /* (6): rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ 447 /* (4): signal, blocked, sigignore, sigcatch */ 448 /* (4): wchan, nswap, cnswap, exit_signal */ 449 cp = skip_fields(cp, 14); 450 //FIXME: is it safe to assume this field exists? 451 sp->last_seen_on_cpu = fast_strtoul_10(&cp); 452 # endif 453 #endif /* FEATURE_FAST_TOP */ 454 455 #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS 456 sp->niceness = tasknice; 255 457 #endif 256 458 … … 265 467 else 266 468 sp->state[2] = ' '; 267 268 } 269 469 } 470 471 #if ENABLE_FEATURE_TOPMEM 472 if (flags & PSSCAN_SMAPS) 473 procps_read_smaps(pid, &sp->smaps, NULL, NULL); 474 #endif /* TOPMEM */ 475 #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS 476 if (flags & PSSCAN_RUIDGID) { 477 FILE *file; 478 479 strcpy(filename_tail, "status"); 480 file = fopen_for_read(filename); 481 if (file) { 482 while (fgets(buf, sizeof(buf), file)) { 483 char *tp; 484 #define SCAN_TWO(str, name, statement) \ 485 if (strncmp(buf, str, sizeof(str)-1) == 0) { \ 486 tp = skip_whitespace(buf + sizeof(str)-1); \ 487 sscanf(tp, "%u", &sp->name); \ 488 statement; \ 489 } 490 SCAN_TWO("Uid:", ruid, continue); 491 SCAN_TWO("Gid:", rgid, break); 492 #undef SCAN_TWO 493 } 494 fclose(file); 495 } 496 } 497 #endif /* PS_ADDITIONAL_COLUMNS */ 498 if (flags & PSSCAN_EXE) { 499 strcpy(filename_tail, "exe"); 500 free(sp->exe); 501 sp->exe = xmalloc_readlink(filename); 502 } 503 /* Note: if /proc/PID/cmdline is empty, 504 * code below "breaks". Therefore it must be 505 * the last code to parse /proc/PID/xxx data 506 * (we used to have /proc/PID/exe parsing after it 507 * and were getting stale sp->exe). 508 */ 270 509 #if 0 /* PSSCAN_CMD is not used */ 271 510 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"); 511 free(sp->argv0); 512 sp->argv0 = NULL; 513 free(sp->cmd); 514 sp->cmd = NULL; 515 strcpy(filename_tail, "cmdline"); 281 516 /* TODO: to get rid of size limits, read into malloc buf, 282 517 * then realloc it down to real size. */ … … 296 531 } 297 532 #else 298 if (flags & PSSCAN_ARGV0) { 299 if (sp->argv0) { 300 free(sp->argv0); 301 sp->argv0 = NULL; 302 } 303 strcpy(filename_tail, "/cmdline"); 533 if (flags & (PSSCAN_ARGV0|PSSCAN_ARGVN)) { 534 free(sp->argv0); 535 sp->argv0 = NULL; 536 strcpy(filename_tail, "cmdline"); 304 537 n = read_to_buf(filename, buf); 305 538 if (n <= 0) 306 539 break; 307 if (flags & PSSCAN_ARGV0) 540 if (flags & PSSCAN_ARGVN) { 541 sp->argv_len = n; 542 sp->argv0 = xmalloc(n + 1); 543 memcpy(sp->argv0, buf, n + 1); 544 /* sp->argv0[n] = '\0'; - buf has it */ 545 } else { 546 sp->argv_len = 0; 308 547 sp->argv0 = xstrdup(buf); 548 } 309 549 } 310 550 #endif 311 551 break; 312 } 552 } /* for (;;) */ 553 313 554 return sp; 314 555 } 315 556 316 void read_cmdline(char *buf, int col, unsigned pid, const char *comm)317 { 318 ssize_t sz;557 void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) 558 { 559 int sz; 319 560 char filename[sizeof("/proc//cmdline") + sizeof(int)*3]; 320 561 321 562 sprintf(filename, "/proc/%u/cmdline", pid); 322 sz = open_read_close(filename, buf, col );563 sz = open_read_close(filename, buf, col - 1); 323 564 if (sz > 0) { 324 565 buf[sz] = '\0'; 325 while (--sz >= 0) 566 while (--sz >= 0 && buf[sz] == '\0') 567 continue; 568 do { 326 569 if ((unsigned char)(buf[sz]) < ' ') 327 570 buf[sz] = ' '; 571 } while (--sz >= 0); 328 572 } else { 329 573 snprintf(buf, col, "[%s]", comm);
Note:
See TracChangeset
for help on using the changeset viewer.