Changeset 1765 in MondoRescue for branches/2.2.5/mindi-busybox/libbb/procps.c


Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (17 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.5/mindi-busybox/libbb/procps.c

    r821 r1765  
    55 * Copyright 1998 by Albert Cahalan; all rights reserved.
    66 * Copyright (C) 2002 by Vladimir Oleynik <dzo@simtreas.ru>
     7 * SELinux support: (c) 2007 by Yuichi Nakamura <ynakam@hitachisoft.jp>
    78 *
    89 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    910 */
    1011
    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 
    1812#include "libbb.h"
    1913
    2014
     15typedef struct unsigned_to_name_map_t {
     16    unsigned id;
     17    char name[USERNAME_MAX_SIZE];
     18} unsigned_to_name_map_t;
     19
     20typedef struct cache_t {
     21    unsigned_to_name_map_t *cache;
     22    int size;
     23} cache_t;
     24
     25static cache_t username, groupname;
     26
     27static void clear_cache(cache_t *cp)
     28{
     29    free(cp->cache);
     30    cp->cache = NULL;
     31    cp->size = 0;
     32}
     33void 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 */
     42static 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
     55typedef char* ug_func(char *name, int bufsize, long uid);
     56static 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}
     69const char* get_cached_username(uid_t uid)
     70{
     71    return get_cached(&username, uid, bb_getpwuid);
     72}
     73const char* get_cached_groupname(gid_t gid)
     74{
     75    return get_cached(&groupname, gid, bb_getgrgid);
     76}
     77
     78
    2179#define PROCPS_BUFSIZE 1024
    2280
     
    2482{
    2583    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;
    2887    fd = open(filename, O_RDONLY);
    29     if(fd < 0)
    30         return -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';
    3493    return ret;
    3594}
    3695
    37 
    38 procps_status_t * procps_scan(int save_user_arg0)
    39 {
    40     static DIR *dir;
     96procps_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
     103void 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 */
     113static 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}
     125static 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
     136void BUG_comm_size(void);
     137procps_status_t *procps_scan(procps_status_t* sp, int flags)
     138{
    41139    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;
    44145    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;
    51146    struct stat sb;
    52147
    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;
    55312    }
    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
     316void 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);
    149330    }
    150331}
     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,
     368the rest is some obsolete cruft
     369*/
Note: See TracChangeset for help on using the changeset viewer.