Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/libbb/procps.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 815 by niro, Sat Sep 1 22:45:15 2007 UTC revision 816 by niro, Fri Apr 24 18:33:46 2009 UTC
# Line 4  Line 4 
4   *   *
5   * Copyright 1998 by Albert Cahalan; all rights reserved.   * Copyright 1998 by Albert Cahalan; all rights reserved.
6   * Copyright (C) 2002 by Vladimir Oleynik <dzo@simtreas.ru>   * Copyright (C) 2002 by Vladimir Oleynik <dzo@simtreas.ru>
7     * SELinux support: (c) 2007 by Yuichi Nakamura <ynakam@hitachisoft.jp>
8   *   *
9   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10   */   */
# Line 29  static void clear_cache(cache_t *cp) Line 30  static void clear_cache(cache_t *cp)
30   cp->cache = NULL;   cp->cache = NULL;
31   cp->size = 0;   cp->size = 0;
32  }  }
33  void clear_username_cache(void)  void FAST_FUNC clear_username_cache(void)
34  {  {
35   clear_cache(&username);   clear_cache(&username);
36   clear_cache(&groupname);   clear_cache(&groupname);
# Line 45  static int get_cached(cache_t *cp, unsig Line 46  static int get_cached(cache_t *cp, unsig
46   if (cp->cache[i].id == id)   if (cp->cache[i].id == id)
47   return i;   return i;
48   i = cp->size++;   i = cp->size++;
49   cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache));   cp->cache = xrealloc_vector(cp->cache, 2, i);
50   cp->cache[i++].id = id;   cp->cache[i++].id = id;
51   return -i;   return -i;
52  }  }
53  #endif  #endif
54    
55  typedef char* ug_func(char *name, long uid, int bufsize);  typedef char* FAST_FUNC ug_func(char *name, int bufsize, long uid);
56  static char* get_cached(cache_t *cp, unsigned id, ug_func* fp)  static char* get_cached(cache_t *cp, unsigned id, ug_func* fp)
57  {  {
58   int i;   int i;
# Line 59  static char* get_cached(cache_t *cp, uns Line 60  static char* get_cached(cache_t *cp, uns
60   if (cp->cache[i].id == id)   if (cp->cache[i].id == id)
61   return cp->cache[i].name;   return cp->cache[i].name;
62   i = cp->size++;   i = cp->size++;
63   cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache));   cp->cache = xrealloc_vector(cp->cache, 2, i);
64   cp->cache[i].id = id;   cp->cache[i].id = id;
65   fp(cp->cache[i].name, id, sizeof(cp->cache[i].name));   /* 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;   return cp->cache[i].name;
68  }  }
69  const char* get_cached_username(uid_t uid)  const char* FAST_FUNC get_cached_username(uid_t uid)
70  {  {
71   return get_cached(&username, uid, bb_getpwuid);   return get_cached(&username, uid, bb_getpwuid);
72  }  }
73  const char* get_cached_groupname(gid_t gid)  const char* FAST_FUNC get_cached_groupname(gid_t gid)
74  {  {
75   return get_cached(&groupname, gid, bb_getgrgid);   return get_cached(&groupname, gid, bb_getgrgid);
76  }  }
# Line 78  const char* get_cached_groupname(gid_t g Line 80  const char* get_cached_groupname(gid_t g
80    
81  static int read_to_buf(const char *filename, void *buf)  static int read_to_buf(const char *filename, void *buf)
82  {  {
83   ssize_t ret;   int fd;
84   ret = open_read_close(filename, buf, PROCPS_BUFSIZE-1);   /* 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;
87     fd = open(filename, O_RDONLY);
88     if (fd >= 0) {
89     ret = read(fd, buf, PROCPS_BUFSIZE-1);
90     close(fd);
91     }
92   ((char *)buf)[ret > 0 ? ret : 0] = '\0';   ((char *)buf)[ret > 0 ? ret : 0] = '\0';
93   return ret;   return ret;
94  }  }
95    
96  procps_status_t* alloc_procps_scan(int flags)  static procps_status_t* FAST_FUNC alloc_procps_scan(void)
97  {  {
98     unsigned n = getpagesize();
99   procps_status_t* sp = xzalloc(sizeof(procps_status_t));   procps_status_t* sp = xzalloc(sizeof(procps_status_t));
100   sp->dir = xopendir("/proc");   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;
107   return sp;   return sp;
108  }  }
109    
110  void free_procps_scan(procps_status_t* sp)  void FAST_FUNC free_procps_scan(procps_status_t* sp)
111  {  {
112   closedir(sp->dir);   closedir(sp->dir);
113   free(sp->cmd);   free(sp->argv0);
114     USE_SELINUX(free(sp->context);)
115   free(sp);   free(sp);
116  }  }
117    
118    #if ENABLE_FEATURE_TOPMEM
119    static unsigned long fast_strtoul_16(char **endptr)
120    {
121     unsigned char c;
122     char *str = *endptr;
123     unsigned long n = 0;
124    
125     while ((c = *str++) != ' ') {
126     c = ((c|0x20) - '0');
127     if (c > 9)
128     // c = c + '0' - 'a' + 10:
129     c = c - ('a' - '0' - 10);
130     n = n*16 + c;
131     }
132     *endptr = str; /* We skip trailing space! */
133     return n;
134    }
135    /* TOPMEM uses fast_strtoul_10, so... */
136    #undef ENABLE_FEATURE_FAST_TOP
137    #define ENABLE_FEATURE_FAST_TOP 1
138    #endif
139    
140    #if ENABLE_FEATURE_FAST_TOP
141    /* We cut a lot of corners here for speed */
142    static unsigned long fast_strtoul_10(char **endptr)
143    {
144     char c;
145     char *str = *endptr;
146     unsigned long n = *str - '0';
147    
148     while ((c = *++str) != ' ')
149     n = n*10 + (c - '0');
150    
151     *endptr = str + 1; /* We skip trailing space! */
152     return n;
153    }
154    static char *skip_fields(char *str, int count)
155    {
156     do {
157     while (*str++ != ' ')
158     continue;
159     /* we found a space char, str points after it */
160     } while (--count);
161     return str;
162    }
163    #endif
164    
165  void BUG_comm_size(void);  void BUG_comm_size(void);
166  procps_status_t* procps_scan(procps_status_t* sp, int flags)  procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
167  {  {
168   struct dirent *entry;   struct dirent *entry;
169   char buf[PROCPS_BUFSIZE];   char buf[PROCPS_BUFSIZE];
# Line 111  procps_status_t* procps_scan(procps_stat Line 175  procps_status_t* procps_scan(procps_stat
175   struct stat sb;   struct stat sb;
176    
177   if (!sp)   if (!sp)
178   sp = alloc_procps_scan(flags);   sp = alloc_procps_scan();
179    
180   for (;;) {   for (;;) {
181   entry = readdir(sp->dir);   entry = readdir(sp->dir);
# Line 127  procps_status_t* procps_scan(procps_stat Line 191  procps_status_t* procps_scan(procps_stat
191   * ("continue" would mean that current /proc/NNN   * ("continue" would mean that current /proc/NNN
192   * is not a valid process info) */   * is not a valid process info) */
193    
194   memset(&sp->rss, 0, sizeof(*sp) - offsetof(procps_status_t, rss));   memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz));
195    
196   sp->pid = pid;   sp->pid = pid;
197   if (!(flags & ~PSSCAN_PID)) break;   if (!(flags & ~PSSCAN_PID)) break;
198    
199    #if ENABLE_SELINUX
200     if (flags & PSSCAN_CONTEXT) {
201     if (getpidcon(sp->pid, &sp->context) < 0)
202     sp->context = NULL;
203     }
204    #endif
205    
206   filename_tail = filename + sprintf(filename, "/proc/%d", pid);   filename_tail = filename + sprintf(filename, "/proc/%d", pid);
207    
208   if (flags & PSSCAN_UIDGID) {   if (flags & PSSCAN_UIDGID) {
# Line 143  procps_status_t* procps_scan(procps_stat Line 214  procps_status_t* procps_scan(procps_stat
214   }   }
215    
216   if (flags & PSSCAN_STAT) {   if (flags & PSSCAN_STAT) {
217   char *cp;   char *cp, *comm1;
218     int tty;
219    #if !ENABLE_FEATURE_FAST_TOP
220     unsigned long vsz, rss;
221    #endif
222   /* see proc(5) for some details on this */   /* see proc(5) for some details on this */
223   strcpy(filename_tail, "/stat");   strcpy(filename_tail, "/stat");
224   n = read_to_buf(filename, buf);   n = read_to_buf(filename, buf);
225   if (n < 0)   if (n < 0)
226   break;   break;
227   cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */   cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
228   if (!cp || cp[1] != ' ')   /*if (!cp || cp[1] != ' ')
229   break;   break;*/
230   cp[0] = '\0';   cp[0] = '\0';
231   if (sizeof(sp->comm) < 16)   if (sizeof(sp->comm) < 16)
232   BUG_comm_size();   BUG_comm_size();
233   sscanf(buf, "%*s (%15c", sp->comm);   comm1 = strchr(buf, '(');
234     /*if (comm1)*/
235     safe_strncpy(sp->comm, comm1 + 1, sizeof(sp->comm));
236    
237    #if !ENABLE_FEATURE_FAST_TOP
238   n = sscanf(cp+2,   n = sscanf(cp+2,
239   "%c %u "               /* state, ppid */   "%c %u "               /* state, ppid */
240   "%u %u %*s %*s "       /* pgid, sid, tty, tpgid */   "%u %u %d %*s "        /* pgid, sid, tty, tpgid */
241   "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */   "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
242   "%lu %lu "             /* utime, stime */   "%lu %lu "             /* utime, stime */
243   "%*s %*s %*s "         /* cutime, cstime, priority */   "%*s %*s %*s "         /* cutime, cstime, priority */
244   "%ld "                 /* nice */   "%ld "                 /* nice */
245   "%*s %*s %*s "         /* timeout, it_real_value, start_time */   "%*s %*s "             /* timeout, it_real_value */
246   "%*s "                 /* vsize */   "%lu "                 /* start_time */
247   "%lu",                 /* rss */   "%lu "                 /* vsize */
248     "%lu "                 /* rss */
249    #if ENABLE_FEATURE_TOP_SMP_PROCESS
250     "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
251     "%*s %*s %*s %*s "         /*signal, blocked, sigignore, sigcatch */
252     "%*s %*s %*s %*s "         /*wchan, nswap, cnswap, exit_signal */
253     "%d"                       /*cpu last seen on*/
254    #endif
255     ,
256   sp->state, &sp->ppid,   sp->state, &sp->ppid,
257   &sp->pgid, &sp->sid,   &sp->pgid, &sp->sid, &tty,
258   &sp->utime, &sp->stime,   &sp->utime, &sp->stime,
259   &tasknice,   &tasknice,
260   &sp->rss);   &sp->start_time,
261   if (n != 8)   &vsz,
262     &rss
263    #if ENABLE_FEATURE_TOP_SMP_PROCESS
264     , &sp->last_seen_on_cpu
265    #endif
266     );
267    
268     if (n < 11)
269   break;   break;
270    #if ENABLE_FEATURE_TOP_SMP_PROCESS
271     if (n < 11+15)
272     sp->last_seen_on_cpu = 0;
273    #endif
274    
275   if (sp->rss == 0 && sp->state[0] != 'Z')   /* vsz is in bytes and we want kb */
276     sp->vsz = vsz >> 10;
277     /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */
278     sp->rss = rss << sp->shift_pages_to_kb;
279     sp->tty_major = (tty >> 8) & 0xfff;
280     sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00);
281    #else
282    /* This costs ~100 bytes more but makes top faster by 20%
283     * If you run 10000 processes, this may be important for you */
284     sp->state[0] = cp[2];
285     cp += 4;
286     sp->ppid = fast_strtoul_10(&cp);
287     sp->pgid = fast_strtoul_10(&cp);
288     sp->sid = fast_strtoul_10(&cp);
289     tty = fast_strtoul_10(&cp);
290     sp->tty_major = (tty >> 8) & 0xfff;
291     sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00);
292     cp = skip_fields(cp, 6); /* tpgid, flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
293     sp->utime = fast_strtoul_10(&cp);
294     sp->stime = fast_strtoul_10(&cp);
295     cp = skip_fields(cp, 3); /* cutime, cstime, priority */
296     tasknice = fast_strtoul_10(&cp);
297     cp = skip_fields(cp, 2); /* timeout, it_real_value */
298     sp->start_time = fast_strtoul_10(&cp);
299     /* vsz is in bytes and we want kb */
300     sp->vsz = fast_strtoul_10(&cp) >> 10;
301     /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */
302     sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb;
303    #if ENABLE_FEATURE_TOP_SMP_PROCESS
304     /* (6): rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
305     /* (4): signal, blocked, sigignore, sigcatch */
306     /* (4): wchan, nswap, cnswap, exit_signal */
307     cp = skip_fields(cp, 14);
308    //FIXME: is it safe to assume this field exists?
309     sp->last_seen_on_cpu = fast_strtoul_10(&cp);
310    #endif
311    #endif /* end of !ENABLE_FEATURE_TOP_SMP_PROCESS */
312    
313     if (sp->vsz == 0 && sp->state[0] != 'Z')
314   sp->state[1] = 'W';   sp->state[1] = 'W';
315   else   else
316   sp->state[1] = ' ';   sp->state[1] = ' ';
317   if (tasknice < 0)   if (tasknice < 0)
318   sp->state[2] = '<';   sp->state[2] = '<';
319   else if (tasknice > 0)   else if (tasknice) /* > 0 */
320   sp->state[2] = 'N';   sp->state[2] = 'N';
321   else   else
322   sp->state[2] = ' ';   sp->state[2] = ' ';
323     }
324    
325  #ifdef PAGE_SHIFT  #if ENABLE_FEATURE_TOPMEM
326   sp->rss <<= (PAGE_SHIFT - 10);     /* 2**10 = 1kb */   if (flags & (PSSCAN_SMAPS)) {
327  #else   FILE *file;
328   sp->rss *= (getpagesize() >> 10);     /* 2**10 = 1kb */  
329  #endif   strcpy(filename_tail, "/smaps");
330     file = fopen_for_read(filename);
331     if (!file)
332     break;
333     while (fgets(buf, sizeof(buf), file)) {
334     unsigned long sz;
335     char *tp;
336     char w;
337    #define SCAN(str, name) \
338     if (strncmp(buf, str, sizeof(str)-1) == 0) { \
339     tp = skip_whitespace(buf + sizeof(str)-1); \
340     sp->name += fast_strtoul_10(&tp); \
341     continue; \
342     }
343     SCAN("Shared_Clean:" , shared_clean );
344     SCAN("Shared_Dirty:" , shared_dirty );
345     SCAN("Private_Clean:", private_clean);
346     SCAN("Private_Dirty:", private_dirty);
347    #undef SCAN
348     // f7d29000-f7d39000 rw-s ADR M:m OFS FILE
349     tp = strchr(buf, '-');
350     if (tp) {
351     *tp = ' ';
352     tp = buf;
353     sz = fast_strtoul_16(&tp); /* start */
354     sz = (fast_strtoul_16(&tp) - sz) >> 10; /* end - start */
355     // tp -> "rw-s" string
356     w = tp[1];
357     // skipping "rw-s ADR M:m OFS "
358     tp = skip_whitespace(skip_fields(tp, 4));
359     // filter out /dev/something (something != zero)
360     if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) {
361     if (w == 'w') {
362     sp->mapped_rw += sz;
363     } else if (w == '-') {
364     sp->mapped_ro += sz;
365     }
366     }
367    //else printf("DROPPING %s (%s)\n", buf, tp);
368     if (strcmp(tp, "[stack]\n") == 0)
369     sp->stack += sz;
370     }
371     }
372     fclose(file);
373   }   }
374    #endif /* TOPMEM */
375    
376   if (flags & PSSCAN_CMD) {  #if 0 /* PSSCAN_CMD is not used */
377     if (flags & (PSSCAN_CMD|PSSCAN_ARGV0)) {
378     free(sp->argv0);
379     sp->argv0 = NULL;
380   free(sp->cmd);   free(sp->cmd);
381   sp->cmd = NULL;   sp->cmd = NULL;
382   strcpy(filename_tail, "/cmdline");   strcpy(filename_tail, "/cmdline");
383     /* TODO: to get rid of size limits, read into malloc buf,
384     * then realloc it down to real size. */
385   n = read_to_buf(filename, buf);   n = read_to_buf(filename, buf);
386   if (n <= 0)   if (n <= 0)
387   break;   break;
388   if (buf[n-1] == '\n') {   if (flags & PSSCAN_ARGV0)
389   if (!--n)   sp->argv0 = xstrdup(buf);
390   break;   if (flags & PSSCAN_CMD) {
391   buf[n] = '\0';   do {
392     n--;
393     if ((unsigned char)(buf[n]) < ' ')
394     buf[n] = ' ';
395     } while (n);
396     sp->cmd = xstrdup(buf);
397   }   }
  do {  
  n--;  
  if ((unsigned char)(buf[n]) < ' ')  
  buf[n] = ' ';  
  } while (n);  
  sp->cmd = xstrdup(buf);  
398   }   }
399    #else
400     if (flags & (PSSCAN_ARGV0|PSSCAN_ARGVN)) {
401     free(sp->argv0);
402     sp->argv0 = NULL;
403     strcpy(filename_tail, "/cmdline");
404     n = read_to_buf(filename, buf);
405     if (n <= 0)
406     break;
407     if (flags & PSSCAN_ARGVN) {
408     sp->argv_len = n;
409     sp->argv0 = xmalloc(n + 1);
410     memcpy(sp->argv0, buf, n + 1);
411     /* sp->argv0[n] = '\0'; - buf has it */
412     } else {
413     sp->argv_len = 0;
414     sp->argv0 = xstrdup(buf);
415     }
416     }
417    #endif
418   break;   break;
419   }   }
420   return sp;   return sp;
421  }  }
422    
423    void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
424    {
425     ssize_t sz;
426     char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
427    
428     sprintf(filename, "/proc/%u/cmdline", pid);
429     sz = open_read_close(filename, buf, col);
430     if (sz > 0) {
431     buf[sz] = '\0';
432     while (--sz >= 0)
433     if ((unsigned char)(buf[sz]) < ' ')
434     buf[sz] = ' ';
435     } else {
436     snprintf(buf, col, "[%s]", comm);
437     }
438    }
439    
440  /* from kernel:  /* from kernel:
441   //             pid comm S ppid pgid sid tty_nr tty_pgrp flg   //             pid comm S ppid pgid sid tty_nr tty_pgrp flg
442   sprintf(buffer,"%d (%s) %c %d  %d   %d  %d     %d       %lu %lu \   sprintf(buffer,"%d (%s) %c %d  %d   %d  %d     %d       %lu %lu \
# Line 230  procps_status_t* procps_scan(procps_stat Line 452  procps_status_t* procps_scan(procps_stat
452   tty_pgrp,   tty_pgrp,
453   task->flags,   task->flags,
454   min_flt,   min_flt,
   
455   cmin_flt,   cmin_flt,
456   maj_flt,   maj_flt,
457   cmaj_flt,   cmaj_flt,

Legend:
Removed from v.815  
changed lines
  Added in v.816