Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/libbb/procps.c


Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

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

    r1765 r2725  
    77 * SELinux support: (c) 2007 by Yuichi Nakamura <ynakam@hitachisoft.jp>
    88 *
    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.
    1010 */
    1111
     
    1414
    1515typedef struct unsigned_to_name_map_t {
    16     unsigned id;
     16    long id;
    1717    char name[USERNAME_MAX_SIZE];
    1818} unsigned_to_name_map_t;
     
    3131    cp->size = 0;
    3232}
    33 void clear_username_cache(void)
     33void FAST_FUNC clear_username_cache(void)
    3434{
    3535    clear_cache(&username);
     
    4747            return i;
    4848    i = cp->size++;
    49     cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache));
     49    cp->cache = xrealloc_vector(cp->cache, 2, i);
    5050    cp->cache[i++].id = id;
    5151    return -i;
     
    5353#endif
    5454
    55 typedef char* ug_func(char *name, int bufsize, long uid);
    56 static char* get_cached(cache_t *cp, unsigned id, ug_func* fp)
     55static char* get_cached(cache_t *cp, long id,
     56            char* FAST_FUNC x2x_utoa(long id))
    5757{
    5858    int i;
     
    6161            return cp->cache[i].name;
    6262    i = cp->size++;
    63     cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache));
     63    cp->cache = xrealloc_vector(cp->cache, 2, i);
    6464    cp->cache[i].id = id;
    6565    /* 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));
    6767    return cp->cache[i].name;
    6868}
    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);
     69const char* FAST_FUNC get_cached_username(uid_t uid)
     70{
     71    return get_cached(&username, uid, uid2uname_utoa);
     72}
     73const char* FAST_FUNC get_cached_groupname(gid_t gid)
     74{
     75    return get_cached(&groupname, gid, gid2group_utoa);
    7676}
    7777
     
    9494}
    9595
    96 procps_status_t *alloc_procps_scan(int flags)
    97 {
     96static procps_status_t* FAST_FUNC alloc_procps_scan(void)
     97{
     98    unsigned n = getpagesize();
    9899    procps_status_t* sp = xzalloc(sizeof(procps_status_t));
    99100    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;
    100107    return sp;
    101108}
    102109
    103 void free_procps_scan(procps_status_t* sp)
     110void FAST_FUNC free_procps_scan(procps_status_t* sp)
    104111{
    105112    closedir(sp->dir);
     113#if ENABLE_FEATURE_SHOW_THREADS
     114    if (sp->task_dir)
     115        closedir(sp->task_dir);
     116#endif
    106117    free(sp->argv0);
    107     USE_SELINUX(free(sp->context);)
     118    free(sp->exe);
     119    IF_SELINUX(free(sp->context);)
    108120    free(sp);
    109121}
    110122
    111 #if ENABLE_FEATURE_FAST_TOP
     123#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
     124static 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
    112143/* We cut a lot of corners here for speed */
    113144static unsigned long fast_strtoul_10(char **endptr)
     
    123154    return n;
    124155}
     156
     157# if ENABLE_FEATURE_FAST_TOP
     158static 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
    125168static char *skip_fields(char *str, int count)
    126169{
     
    134177#endif
    135178
     179#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
     180int 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
    136284void BUG_comm_size(void);
    137 procps_status_t *procps_scan(procps_status_t* sp, int flags)
     285procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
    138286{
    139287    struct dirent *entry;
     
    147295
    148296    if (!sp)
    149         sp = alloc_procps_scan(flags);
     297        sp = alloc_procps_scan();
    150298
    151299    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
    152309        entry = readdir(sp->dir);
    153310        if (entry == NULL) {
     
    155312            return NULL;
    156313        }
     314 IF_FEATURE_SHOW_THREADS(got_entry:)
    157315        pid = bb_strtou(entry->d_name, NULL, 10);
    158316        if (errno)
    159317            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         */
    164334
    165335        memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz));
    166336
    167337        sp->pid = pid;
    168         if (!(flags & ~PSSCAN_PID)) break;
     338        if (!(flags & ~PSSCAN_PID))
     339            break; /* we needed only pid, we got it */
    169340
    170341#if ENABLE_SELINUX
     
    175346#endif
    176347
    177         filename_tail = filename + sprintf(filename, "/proc/%d", pid);
     348        filename_tail = filename + sprintf(filename, "/proc/%u/", pid);
    178349
    179350        if (flags & PSSCAN_UIDGID) {
    180351            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 */
    183354            sp->uid = sb.st_uid;
    184355            sp->gid = sb.st_gid;
     
    191362            unsigned long vsz, rss;
    192363#endif
    193 
    194364            /* see proc(5) for some details on this */
    195             strcpy(filename_tail, "/stat");
     365            strcpy(filename_tail, "stat");
    196366            n = read_to_buf(filename, buf);
    197367            if (n < 0)
    198                 break;
     368                continue; /* process probably exited */
    199369            cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
    200370            /*if (!cp || cp[1] != ' ')
    201                 break;*/
     371                continue;*/
    202372            cp[0] = '\0';
    203373            if (sizeof(sp->comm) < 16)
     
    215385                "%*s %*s %*s "         /* cutime, cstime, priority */
    216386                "%ld "                 /* nice */
    217                 "%*s %*s %*s "         /* timeout, it_real_value, start_time */
     387                "%*s %*s "             /* timeout, it_real_value */
     388                "%lu "                 /* start_time */
    218389                "%lu "                 /* vsize */
    219390                "%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
    223397                ,
    224398                sp->state, &sp->ppid,
     
    226400                &sp->utime, &sp->stime,
    227401                &tasknice,
     402                &sp->start_time,
    228403                &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;
    234421            sp->tty_major = (tty >> 8) & 0xfff;
    235422            sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00);
     
    249436            sp->stime = fast_strtoul_10(&cp);
    250437            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;
    255457#endif
    256458
     
    265467            else
    266468                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         */
    270509#if 0 /* PSSCAN_CMD is not used */
    271510        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");
    281516            /* TODO: to get rid of size limits, read into malloc buf,
    282517             * then realloc it down to real size. */
     
    296531        }
    297532#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");
    304537            n = read_to_buf(filename, buf);
    305538            if (n <= 0)
    306539                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;
    308547                sp->argv0 = xstrdup(buf);
     548            }
    309549        }
    310550#endif
    311551        break;
    312     }
     552    } /* for (;;) */
     553
    313554    return sp;
    314555}
    315556
    316 void read_cmdline(char *buf, int col, unsigned pid, const char *comm)
    317 {
    318     ssize_t sz;
     557void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
     558{
     559    int sz;
    319560    char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
    320561
    321562    sprintf(filename, "/proc/%u/cmdline", pid);
    322     sz = open_read_close(filename, buf, col);
     563    sz = open_read_close(filename, buf, col - 1);
    323564    if (sz > 0) {
    324565        buf[sz] = '\0';
    325         while (--sz >= 0)
     566        while (--sz >= 0 && buf[sz] == '\0')
     567            continue;
     568        do {
    326569            if ((unsigned char)(buf[sz]) < ' ')
    327570                buf[sz] = ' ';
     571        } while (--sz >= 0);
    328572    } else {
    329573        snprintf(buf, col, "[%s]", comm);
Note: See TracChangeset for help on using the changeset viewer.