source: MondoRescue/branches/stable/mindi-busybox/procps/ps.c @ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 12 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 10.5 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini ps implementation(s) for busybox
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 * Fix for SELinux Support:(c)2007 Hiroshi Shinji <shiroshi@my.email.ne.jp>
7                           (c)2007 Yuichi Nakamura <ynakam@hitachisoft.jp>
8 *
9 * Licensed under the GPL version 2, see the file LICENSE in this tarball.
10 */
11
12#include "libbb.h"
13
14/* Absolute maximum on output line length */
15enum { MAX_WIDTH = 2*1024 };
16
17#if ENABLE_DESKTOP
18
19/* Print value to buf, max size+1 chars (including trailing '\0') */
20
21static void func_user(char *buf, int size, const procps_status_t *ps)
22{
23    safe_strncpy(buf, get_cached_username(ps->uid), size+1);
24}
25
26static void func_comm(char *buf, int size, const procps_status_t *ps)
27{
28    safe_strncpy(buf, ps->comm, size+1);
29}
30
31static void func_args(char *buf, int size, const procps_status_t *ps)
32{
33    read_cmdline(buf, size, ps->pid, ps->comm);
34}
35
36static void func_pid(char *buf, int size, const procps_status_t *ps)
37{
38    sprintf(buf, "%*u", size, ps->pid);
39}
40
41static void func_ppid(char *buf, int size, const procps_status_t *ps)
42{
43    sprintf(buf, "%*u", size, ps->ppid);
44}
45
46static void func_pgid(char *buf, int size, const procps_status_t *ps)
47{
48    sprintf(buf, "%*u", size, ps->pgid);
49}
50
51static void put_u(char *buf, int size, unsigned u)
52{
53    char buf5[5];
54    smart_ulltoa5( ((unsigned long long)u) << 10, buf5);
55    sprintf(buf, "%.*s", size, buf5);
56}
57
58static void func_vsz(char *buf, int size, const procps_status_t *ps)
59{
60    put_u(buf, size, ps->vsz);
61}
62
63static void func_rss(char *buf, int size, const procps_status_t *ps)
64{
65    put_u(buf, size, ps->rss);
66}
67
68static void func_tty(char *buf, int size, const procps_status_t *ps)
69{
70    buf[0] = '?';
71    buf[1] = '\0';
72    if (ps->tty_major) /* tty field of "0" means "no tty" */
73        snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor);
74}
75
76#if ENABLE_SELINUX
77static void func_label(char *buf, int size, const procps_status_t *ps)
78{
79    safe_strncpy(buf, ps->context ? ps->context : "unknown", size+1);
80}
81#endif
82
83/*
84static void func_nice(char *buf, int size, const procps_status_t *ps)
85{
86    ps->???
87}
88
89static void func_etime(char *buf, int size, const procps_status_t *ps)
90{
91    elapled time [[dd-]hh:]mm:ss
92}
93
94static void func_time(char *buf, int size, const procps_status_t *ps)
95{
96    cumulative time [[dd-]hh:]mm:ss
97}
98
99static void func_pcpu(char *buf, int size, const procps_status_t *ps)
100{
101}
102*/
103
104typedef struct {
105    uint16_t width;
106    char name[6];
107    const char *header;
108    void (*f)(char *buf, int size, const procps_status_t *ps);
109    int ps_flags;
110} ps_out_t;
111
112static const ps_out_t out_spec[] = {
113// Mandated by POSIX:
114    { 8                  , "user"  ,"USER"   ,func_user  ,PSSCAN_UIDGID  },
115    { 16                 , "comm"  ,"COMMAND",func_comm  ,PSSCAN_COMM    },
116    { 256                , "args"  ,"COMMAND",func_args  ,PSSCAN_COMM    },
117    { 5                  , "pid"   ,"PID"    ,func_pid   ,PSSCAN_PID     },
118    { 5                  , "ppid"  ,"PPID"   ,func_ppid  ,PSSCAN_PPID    },
119    { 5                  , "pgid"  ,"PGID"   ,func_pgid  ,PSSCAN_PGID    },
120//  { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_        },
121//  { sizeof("GROUP"  )-1, "group" ,"GROUP"  ,func_group ,PSSCAN_UIDGID  },
122//  { sizeof("NI"     )-1, "nice"  ,"NI"     ,func_nice  ,PSSCAN_        },
123//  { sizeof("%CPU"   )-1, "pcpu"  ,"%CPU"   ,func_pcpu  ,PSSCAN_        },
124//  { sizeof("RGROUP" )-1, "rgroup","RGROUP" ,func_rgroup,PSSCAN_UIDGID  },
125//  { sizeof("RUSER"  )-1, "ruser" ,"RUSER"  ,func_ruser ,PSSCAN_UIDGID  },
126//  { sizeof("TIME"   )-1, "time"  ,"TIME"   ,func_time  ,PSSCAN_        },
127    { 6                  , "tty"   ,"TT"     ,func_tty   ,PSSCAN_TTY     },
128    { 4                  , "vsz"   ,"VSZ"    ,func_vsz   ,PSSCAN_VSZ     },
129// Not mandated by POSIX, but useful:
130    { 4                  , "rss"   ,"RSS"    ,func_rss   ,PSSCAN_RSS     },
131#if ENABLE_SELINUX
132    { 35                 , "label" ,"LABEL"  ,func_label ,PSSCAN_CONTEXT },
133#endif
134};
135
136#if ENABLE_SELINUX
137#define SELINIX_O_PREFIX "label,"
138#define DEFAULT_O_STR    SELINIX_O_PREFIX "pid,user" /* TODO: ,vsz,stat */ ",args"
139#else
140#define DEFAULT_O_STR    "pid,user" /* TODO: ,vsz,stat */ ",args"
141#endif
142
143struct globals {
144    ps_out_t* out;
145    int out_cnt;
146    int print_header;
147    int need_flags;
148    char *buffer;
149    unsigned terminal_width;
150    char default_o[sizeof(DEFAULT_O_STR)];
151};
152#define G (*(struct globals*)&bb_common_bufsiz1)
153#define out            (G.out           )
154#define out_cnt        (G.out_cnt       )
155#define print_header   (G.print_header  )
156#define need_flags     (G.need_flags    )
157#define buffer         (G.buffer        )
158#define terminal_width (G.terminal_width)
159#define default_o      (G.default_o     )
160
161static ps_out_t* new_out_t(void)
162{
163    int i = out_cnt++;
164    out = xrealloc(out, out_cnt * sizeof(*out));
165    return &out[i];
166}
167
168static const ps_out_t* find_out_spec(const char *name)
169{
170    int i;
171    for (i = 0; i < ARRAY_SIZE(out_spec); i++) {
172        if (!strcmp(name, out_spec[i].name))
173            return &out_spec[i];
174    }
175    bb_error_msg_and_die("bad -o argument '%s'", name);
176}
177
178static void parse_o(char* opt)
179{
180    ps_out_t* new;
181    // POSIX: "-o is blank- or comma-separated list" (FIXME)
182    char *comma, *equal;
183    while (1) {
184        comma = strchr(opt, ',');
185        equal = strchr(opt, '=');
186        if (comma && (!equal || equal > comma)) {
187            *comma = '\0';
188            *new_out_t() = *find_out_spec(opt);
189            *comma = ',';
190            opt = comma + 1;
191            continue;
192        }
193        break;
194    }
195    // opt points to last spec in comma separated list.
196    // This one can have =HEADER part.
197    new = new_out_t();
198    if (equal)
199        *equal = '\0';
200    *new = *find_out_spec(opt);
201    if (equal) {
202        *equal = '=';
203        new->header = equal + 1;
204        // POSIX: the field widths shall be ... at least as wide as
205        // the header text (default or overridden value).
206        // If the header text is null, such as -o user=,
207        // the field width shall be at least as wide as the
208        // default header text
209        if (new->header[0]) {
210            new->width = strlen(new->header);
211            print_header = 1;
212        }
213    } else
214        print_header = 1;
215}
216
217static void post_process(void)
218{
219    int i;
220    int width = 0;
221    for (i = 0; i < out_cnt; i++) {
222        need_flags |= out[i].ps_flags;
223        if (out[i].header[0]) {
224            print_header = 1;
225        }
226        width += out[i].width + 1; /* "FIELD " */
227    }
228#if ENABLE_SELINUX
229    if (!is_selinux_enabled())
230        need_flags &= ~PSSCAN_CONTEXT;
231#endif
232    buffer = xmalloc(width + 1); /* for trailing \0 */
233}
234
235static void format_header(void)
236{
237    int i;
238    ps_out_t* op;
239    char *p;
240
241    if (!print_header)
242        return;
243    p = buffer;
244    i = 0;
245    if (out_cnt) {
246        while (1) {
247            op = &out[i];
248            if (++i == out_cnt) /* do not pad last field */
249                break;
250            p += sprintf(p, "%-*s ", op->width, op->header);
251        }
252        strcpy(p, op->header);
253    }
254    printf("%.*s\n", terminal_width, buffer);
255}
256
257static void format_process(const procps_status_t *ps)
258{
259    int i, len;
260    char *p = buffer;
261    i = 0;
262    if (out_cnt) while (1) {
263        out[i].f(p, out[i].width, ps);
264        // POSIX: Any field need not be meaningful in all
265        // implementations. In such a case a hyphen ( '-' )
266        // should be output in place of the field value.
267        if (!p[0]) {
268            p[0] = '-';
269            p[1] = '\0';
270        }
271        len = strlen(p);
272        p += len;
273        len = out[i].width - len + 1;
274        if (++i == out_cnt) /* do not pad last field */
275            break;
276        p += sprintf(p, "%*s", len, "");
277    }
278    printf("%.*s\n", terminal_width, buffer);
279}
280
281int ps_main(int argc, char **argv);
282int ps_main(int argc, char **argv)
283{
284    procps_status_t *p;
285    llist_t* opt_o = NULL;
286    USE_SELINUX(int opt;)
287
288    // POSIX:
289    // -a  Write information for all processes associated with terminals
290    //     Implementations may omit session leaders from this list
291    // -A  Write information for all processes
292    // -d  Write information for all processes, except session leaders
293    // -e  Write information for all processes (equivalent to -A.)
294    // -f  Generate a full listing
295    // -l  Generate a long listing
296    // -o col1,col2,col3=header
297    //     Select which columns to display
298    /* We allow (and ignore) most of the above. FIXME */
299    opt_complementary = "o::";
300    USE_SELINUX(opt =) getopt32(argv, "Zo:aAdefl", &opt_o);
301    if (opt_o) {
302        do {
303            parse_o(opt_o->data);
304            opt_o = opt_o->link;
305        } while (opt_o);
306    } else {
307        /* Below: parse_o() needs char*, NOT const char*... */
308#if ENABLE_SELINUX
309        if (!(opt & 1) || !is_selinux_enabled()) {
310            /* no -Z or no SELinux: do not show LABEL */
311            strcpy(default_o, DEFAULT_O_STR + sizeof(SELINIX_O_PREFIX)-1);
312        } else
313#endif
314        {
315            strcpy(default_o, DEFAULT_O_STR);
316        }
317        parse_o(default_o);
318    }
319    post_process();
320
321    /* Was INT_MAX, but some libc's go belly up with printf("%.*s")
322     * and such large widths */
323    terminal_width = MAX_WIDTH;
324    if (isatty(1)) {
325        get_terminal_width_height(0, &terminal_width, NULL);
326        if (--terminal_width > MAX_WIDTH)
327            terminal_width = MAX_WIDTH;
328    }
329    format_header();
330
331    p = NULL;
332    while ((p = procps_scan(p, need_flags))) {
333        format_process(p);
334    }
335
336    return EXIT_SUCCESS;
337}
338
339
340#else /* !ENABLE_DESKTOP */
341
342
343int ps_main(int argc, char **argv);
344int ps_main(int argc, char **argv)
345{
346    procps_status_t *p = NULL;
347    int len;
348    SKIP_SELINUX(const) int use_selinux = 0;
349    USE_SELINUX(int i;)
350#if !ENABLE_FEATURE_PS_WIDE
351    enum { terminal_width = 79 };
352#else
353    int terminal_width;
354    int w_count = 0;
355#endif
356
357#if ENABLE_FEATURE_PS_WIDE || ENABLE_SELINUX
358#if ENABLE_FEATURE_PS_WIDE
359    opt_complementary = "-:ww";
360    USE_SELINUX(i =) getopt32(argv, USE_SELINUX("Z") "w", &w_count);
361    /* if w is given once, GNU ps sets the width to 132,
362     * if w is given more than once, it is "unlimited"
363     */
364    if (w_count) {
365        terminal_width = (w_count==1) ? 132 : MAX_WIDTH;
366    } else {
367        get_terminal_width_height(0, &terminal_width, NULL);
368        /* Go one less... */
369        if (--terminal_width > MAX_WIDTH)
370            terminal_width = MAX_WIDTH;
371    }
372#else /* only ENABLE_SELINUX */
373    i = getopt32(argv, "Z");
374#endif
375#if ENABLE_SELINUX
376    if ((i & 1) && is_selinux_enabled())
377        use_selinux = PSSCAN_CONTEXT;
378#endif
379#endif /* ENABLE_FEATURE_PS_WIDE || ENABLE_SELINUX */
380
381    if (use_selinux)
382        puts("  PID Context                          Stat Command");
383    else
384        puts("  PID  Uid        VSZ Stat Command");
385
386    while ((p = procps_scan(p, 0
387            | PSSCAN_PID
388            | PSSCAN_UIDGID
389            | PSSCAN_STATE
390            | PSSCAN_VSZ
391            | PSSCAN_COMM
392            | use_selinux
393    ))) {
394#if ENABLE_SELINUX
395        if (use_selinux) {
396            len = printf("%5u %-32s %s ",
397                    p->pid,
398                    p->context ? p->context : "unknown",
399                    p->state);
400        } else
401#endif
402        {
403            const char *user = get_cached_username(p->uid);
404            if (p->vsz == 0)
405                len = printf("%5u %-8s        %s ",
406                    p->pid, user, p->state);
407            else
408                len = printf("%5u %-8s %6u %s ",
409                    p->pid, user, p->vsz, p->state);
410        }
411
412        {
413            int sz = terminal_width - len;
414            char buf[sz + 1];
415            read_cmdline(buf, sz, p->pid, p->comm);
416            puts(buf);
417        }
418    }
419    if (ENABLE_FEATURE_CLEAN_UP)
420        clear_username_cache();
421    return EXIT_SUCCESS;
422}
423
424#endif /* ENABLE_DESKTOP */
Note: See TracBrowser for help on using the repository browser.