summaryrefslogtreecommitdiff
path: root/busybox/procps
diff options
context:
space:
mode:
authornobody <nobody@localhost>2004-10-13 09:42:10 +0000
committernobody <nobody@localhost>2004-10-13 09:42:10 +0000
commit8c59a0bf0e9e2d87b0ff273ea3f0bf05bbbf6373 (patch)
tree1826706cd4fd009fcd14f4f8021005ec8ec0fa59 /busybox/procps
downloadbusybox-w32-8c59a0bf0e9e2d87b0ff273ea3f0bf05bbbf6373.tar.gz
busybox-w32-8c59a0bf0e9e2d87b0ff273ea3f0bf05bbbf6373.tar.bz2
busybox-w32-8c59a0bf0e9e2d87b0ff273ea3f0bf05bbbf6373.zip
This commit was manufactured by cvs2svn to create tag 'busybox_1_00'.
Diffstat (limited to 'busybox/procps')
-rw-r--r--busybox/procps/Config.in82
-rw-r--r--busybox/procps/Makefile32
-rw-r--r--busybox/procps/Makefile.in43
-rw-r--r--busybox/procps/free.c84
-rw-r--r--busybox/procps/kill.c156
-rw-r--r--busybox/procps/pidof.c71
-rw-r--r--busybox/procps/ps.c109
-rw-r--r--busybox/procps/renice.c54
-rw-r--r--busybox/procps/sysctl.c352
-rw-r--r--busybox/procps/top.c592
-rw-r--r--busybox/procps/uptime.c75
11 files changed, 1650 insertions, 0 deletions
diff --git a/busybox/procps/Config.in b/busybox/procps/Config.in
new file mode 100644
index 000000000..8d557972c
--- /dev/null
+++ b/busybox/procps/Config.in
@@ -0,0 +1,82 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6menu "Process Utilities"
7
8config CONFIG_FREE
9 bool "free"
10 default n
11 help
12 free displays the total amount of free and used physical and swap
13 memory in the system, as well as the buffers used by the kernel.
14 The shared memory column should be ignored; it is obsolete.
15
16config CONFIG_KILL
17 bool "kill"
18 default n
19 help
20 The command kill sends the specified signal to the specified
21 process or process group. If no signal is specified, the TERM
22 signal is sent.
23
24config CONFIG_KILLALL
25 bool "killall"
26 default n
27 depends on CONFIG_KILL
28 help
29 killall sends a signal to all processes running any of the
30 specified commands. If no signal name is specified, SIGTERM is
31 sent.
32
33config CONFIG_PIDOF
34 bool "pidof"
35 default n
36 help
37 Pidof finds the process id's (pids) of the named programs. It prints
38 those id's on the standard output.
39
40config CONFIG_PS
41 bool "ps"
42 default n
43 help
44 ps gives a snapshot of the current processes.
45
46config CONFIG_RENICE
47 bool "renice"
48 default n
49 help
50 Renice alters the scheduling priority of one or more running
51 processes.
52
53config CONFIG_TOP
54 bool "top"
55 default n
56 help
57 The top program provides a dynamic real-time view of a running
58 system.
59
60config FEATURE_CPU_USAGE_PERCENTAGE
61 bool " Support showing CPU usage percentage (add 2k bytes)"
62 default y
63 depends on CONFIG_TOP
64 help
65 Make top display CPU usage.
66
67config CONFIG_UPTIME
68 bool "uptime"
69 default n
70 help
71 uptime gives a one line display of the current time, how long
72 the system has been running, how many users are currently logged
73 on, and the system load averages for the past 1, 5, and 15 minutes.
74
75config CONFIG_SYSCTL
76 bool "sysctl"
77 default n
78 help
79 sysctl - configure kernel parameters at runtime
80
81endmenu
82
diff --git a/busybox/procps/Makefile b/busybox/procps/Makefile
new file mode 100644
index 000000000..1cc880462
--- /dev/null
+++ b/busybox/procps/Makefile
@@ -0,0 +1,32 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20top_srcdir=..
21top_builddir=..
22srcdir=$(top_srcdir)/procps
23PROCPS_DIR:=./
24include $(top_builddir)/Rules.mak
25include $(top_builddir)/.config
26include Makefile.in
27all: $(libraries-y)
28-include $(top_builddir)/.depend
29
30clean:
31 rm -f *.o *.a $(AR_TARGET)
32
diff --git a/busybox/procps/Makefile.in b/busybox/procps/Makefile.in
new file mode 100644
index 000000000..ced29a198
--- /dev/null
+++ b/busybox/procps/Makefile.in
@@ -0,0 +1,43 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20PROCPS_AR:=procps.a
21ifndef $(PROCPS_DIR)
22PROCPS_DIR:=$(top_builddir)/procps/
23endif
24srcdir=$(top_srcdir)/procps
25
26PROCPS-y:=
27PROCPS-$(CONFIG_FREE) += free.o
28PROCPS-$(CONFIG_KILL) += kill.o
29PROCPS-$(CONFIG_PIDOF) += pidof.o
30PROCPS-$(CONFIG_PS) += ps.o
31PROCPS-$(CONFIG_RENICE) += renice.o
32PROCPS-$(CONFIG_SYSCTL) += sysctl.o
33PROCPS-$(CONFIG_TOP) += top.o
34PROCPS-$(CONFIG_UPTIME) += uptime.o
35
36libraries-y+=$(PROCPS_DIR)$(PROCPS_AR)
37
38$(PROCPS_DIR)$(PROCPS_AR): $(patsubst %,$(PROCPS_DIR)%, $(PROCPS-y))
39 $(AR) -ro $@ $(patsubst %,$(PROCPS_DIR)%, $(PROCPS-y))
40
41$(PROCPS_DIR)%.o: $(srcdir)/%.c
42 $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
43
diff --git a/busybox/procps/free.c b/busybox/procps/free.c
new file mode 100644
index 000000000..4fb047d48
--- /dev/null
+++ b/busybox/procps/free.c
@@ -0,0 +1,84 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini free implementation for busybox
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23/* getopt not needed */
24
25#include <stdio.h>
26#include <errno.h>
27#include <stdlib.h>
28#include "busybox.h"
29
30extern int free_main(int argc, char **argv)
31{
32 struct sysinfo info;
33 sysinfo(&info);
34
35 /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */
36 if (info.mem_unit==0) {
37 info.mem_unit=1;
38 }
39 if ( info.mem_unit == 1 ) {
40 info.mem_unit=1024;
41
42 /* TODO: Make all this stuff not overflow when mem >= 4 Gib */
43 info.totalram/=info.mem_unit;
44 info.freeram/=info.mem_unit;
45#ifndef __uClinux__
46 info.totalswap/=info.mem_unit;
47 info.freeswap/=info.mem_unit;
48#endif
49 info.sharedram/=info.mem_unit;
50 info.bufferram/=info.mem_unit;
51 } else {
52 info.mem_unit/=1024;
53 /* TODO: Make all this stuff not overflow when mem >= 4 Gib */
54 info.totalram*=info.mem_unit;
55 info.freeram*=info.mem_unit;
56#ifndef __uClinux__
57 info.totalswap*=info.mem_unit;
58 info.freeswap*=info.mem_unit;
59#endif
60 info.sharedram*=info.mem_unit;
61 info.bufferram*=info.mem_unit;
62 }
63
64 if (argc > 1 && **(argv + 1) == '-')
65 bb_show_usage();
66
67 printf("%6s%13s%13s%13s%13s%13s\n", "", "total", "used", "free",
68 "shared", "buffers");
69
70 printf("%6s%13ld%13ld%13ld%13ld%13ld\n", "Mem:", info.totalram,
71 info.totalram-info.freeram, info.freeram,
72 info.sharedram, info.bufferram);
73
74#ifndef __uClinux__
75 printf("%6s%13ld%13ld%13ld\n", "Swap:", info.totalswap,
76 info.totalswap-info.freeswap, info.freeswap);
77
78 printf("%6s%13ld%13ld%13ld\n", "Total:", info.totalram+info.totalswap,
79 (info.totalram-info.freeram)+(info.totalswap-info.freeswap),
80 info.freeram+info.freeswap);
81#endif
82 return EXIT_SUCCESS;
83}
84
diff --git a/busybox/procps/kill.c b/busybox/procps/kill.c
new file mode 100644
index 000000000..25a8d0124
--- /dev/null
+++ b/busybox/procps/kill.c
@@ -0,0 +1,156 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini kill/killall implementation for busybox
4 *
5 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
6 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <errno.h>
28#include <unistd.h>
29#include <signal.h>
30#include <ctype.h>
31#include <string.h>
32#include <unistd.h>
33#include "busybox.h"
34
35#define KILL 0
36#define KILLALL 1
37
38extern int kill_main(int argc, char **argv)
39{
40 int whichApp, signo = SIGTERM;
41 const char *name;
42 int errors = 0;
43
44#ifdef CONFIG_KILLALL
45 int quiet=0;
46 /* Figure out what we are trying to do here */
47 whichApp = (strcmp(bb_applet_name, "killall") == 0)? KILLALL : KILL;
48#else
49 whichApp = KILL;
50#endif
51
52 /* Parse any options */
53 if (argc < 2)
54 bb_show_usage();
55
56 if(argv[1][0] != '-'){
57 argv++;
58 argc--;
59 goto do_it_now;
60 }
61
62 /* The -l option, which prints out signal names. */
63 if(argv[1][1]=='l' && argv[1][2]=='\0'){
64 if(argc==2) {
65 /* Print the whole signal list */
66 int col = 0;
67 for(signo=1; signo < NSIG; signo++) {
68 name = u_signal_names(0, &signo, 1);
69 if(name==NULL) /* unnamed */
70 continue;
71 col += printf("%2d) %-16s", signo, name);
72 if (col > 60) {
73 printf("\n");
74 col = 0;
75 }
76 }
77 printf("\n");
78
79 } else {
80 for(argv++; *argv; argv++) {
81 name = u_signal_names(*argv, &signo, -1);
82 if(name!=NULL)
83 printf("%s\n", name);
84 }
85 }
86 /* If they specified -l, were all done */
87 return EXIT_SUCCESS;
88 }
89
90#ifdef CONFIG_KILLALL
91 /* The -q quiet option */
92 if(argv[1][1]=='q' && argv[1][2]=='\0'){
93 quiet++;
94 argv++;
95 argc--;
96 if(argc<2 || argv[1][0] != '-'){
97 goto do_it_now;
98 }
99 }
100#endif
101
102 if(!u_signal_names(argv[1]+1, &signo, 0))
103 bb_error_msg_and_die( "bad signal name '%s'", argv[1]+1);
104 argv+=2;
105 argc-=2;
106
107do_it_now:
108
109 if (whichApp == KILL) {
110 /* Looks like they want to do a kill. Do that */
111 while (--argc >= 0) {
112 int pid;
113
114 if (!isdigit(**argv))
115 bb_error_msg_and_die( "Bad PID '%s'", *argv);
116 pid = strtol(*argv, NULL, 0);
117 if (kill(pid, signo) != 0) {
118 bb_perror_msg( "Could not kill pid '%d'", pid);
119 errors++;
120 }
121 argv++;
122 }
123
124 }
125#ifdef CONFIG_KILLALL
126 else {
127 pid_t myPid=getpid();
128 /* Looks like they want to do a killall. Do that */
129 while (--argc >= 0) {
130 long* pidList;
131
132 pidList = find_pid_by_name(*argv);
133 if (!pidList || *pidList<=0) {
134 errors++;
135 if (quiet==0)
136 bb_error_msg( "%s: no process killed", *argv);
137 } else {
138 long *pl;
139
140 for(pl = pidList; *pl !=0 ; pl++) {
141 if (*pl==myPid)
142 continue;
143 if (kill(*pl, signo) != 0) {
144 errors++;
145 if (quiet==0)
146 bb_perror_msg( "Could not kill pid '%ld'", *pl);
147 }
148 }
149 }
150 free(pidList);
151 argv++;
152 }
153 }
154#endif
155 return errors;
156}
diff --git a/busybox/procps/pidof.c b/busybox/procps/pidof.c
new file mode 100644
index 000000000..413864a37
--- /dev/null
+++ b/busybox/procps/pidof.c
@@ -0,0 +1,71 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * pidof implementation for busybox
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <errno.h>
27#include <unistd.h>
28#include <signal.h>
29#include <ctype.h>
30#include <string.h>
31#include <unistd.h>
32#include "busybox.h"
33
34
35extern int pidof_main(int argc, char **argv)
36{
37 int opt, n = 0;
38 int single_flag = 0;
39 int fail = 1;
40
41 /* do normal option parsing */
42 while ((opt = getopt(argc, argv, "s")) > 0) {
43 switch (opt) {
44 case 's':
45 single_flag = 1;
46 break;
47 default:
48 bb_show_usage();
49 }
50 }
51
52 /* Looks like everything is set to go. */
53 while(optind < argc) {
54 long *pidList;
55 long *pl;
56
57 pidList = find_pid_by_name(argv[optind]);
58 for(pl = pidList; *pl > 0; pl++) {
59 printf("%s%ld", (n++ ? " " : ""), *pl);
60 fail = 0;
61 if (single_flag)
62 break;
63 }
64 free(pidList);
65 optind++;
66
67 }
68 printf("\n");
69
70 return fail ? EXIT_FAILURE : EXIT_SUCCESS;
71}
diff --git a/busybox/procps/ps.c b/busybox/procps/ps.c
new file mode 100644
index 000000000..0b603314d
--- /dev/null
+++ b/busybox/procps/ps.c
@@ -0,0 +1,109 @@
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 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <unistd.h>
25#include <dirent.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <ctype.h>
29#include <string.h>
30#include <termios.h>
31#include <sys/ioctl.h>
32#include "busybox.h"
33#ifdef CONFIG_SELINUX
34#include <fs_secure.h>
35#include <ss.h>
36#include <flask_util.h> /* for is_flask_enabled() */
37#endif
38
39static const int TERMINAL_WIDTH = 79; /* not 80 in case terminal has linefold bug */
40
41
42
43extern int ps_main(int argc, char **argv)
44{
45 procps_status_t * p;
46 int i, len;
47 int terminal_width = TERMINAL_WIDTH;
48
49#ifdef CONFIG_SELINUX
50 int use_selinux = 0;
51 security_id_t sid;
52 if(is_flask_enabled() && argv[1] && !strcmp(argv[1], "-c") )
53 use_selinux = 1;
54#endif
55
56 get_terminal_width_height(0, &terminal_width, NULL);
57 /* Go one less... */
58 terminal_width--;
59
60#ifdef CONFIG_SELINUX
61 if(use_selinux)
62 printf(" PID Context Stat Command\n");
63 else
64#endif
65 printf(" PID Uid VmSize Stat Command\n");
66#ifdef CONFIG_SELINUX
67 while ((p = procps_scan(1, use_selinux, &sid)) != 0) {
68#else
69 while ((p = procps_scan(1)) != 0) {
70#endif
71 char *namecmd = p->cmd;
72
73#ifdef CONFIG_SELINUX
74 if(use_selinux)
75 {
76 char sbuf[128];
77 len = sizeof(sbuf);
78 if(security_sid_to_context(sid, (security_context_t)&sbuf, &len))
79 strcpy(sbuf, "unknown");
80
81 len = printf("%5d %-32s %s ", p->pid, sbuf, p->state);
82 }
83 else
84#endif
85 if(p->rss == 0)
86 len = printf("%5d %-8s %s ", p->pid, p->user, p->state);
87 else
88 len = printf("%5d %-8s %6ld %s ", p->pid, p->user, p->rss, p->state);
89 i = terminal_width-len;
90
91 if(namecmd != 0 && namecmd[0] != 0) {
92 if(i < 0)
93 i = 0;
94 if(strlen(namecmd) > i)
95 namecmd[i] = 0;
96 printf("%s\n", namecmd);
97 } else {
98 namecmd = p->short_cmd;
99 if(i < 2)
100 i = 2;
101 if(strlen(namecmd) > (i-2))
102 namecmd[i-2] = 0;
103 printf("[%s]\n", namecmd);
104 }
105 free(p->cmd);
106 }
107 return EXIT_SUCCESS;
108}
109
diff --git a/busybox/procps/renice.c b/busybox/procps/renice.c
new file mode 100644
index 000000000..a6f0820df
--- /dev/null
+++ b/busybox/procps/renice.c
@@ -0,0 +1,54 @@
1/*
2 * Mini renice implementation for busybox
3 *
4 *
5 * Copyright (C) 2000 Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <stdio.h>
24#include <errno.h>
25#include <stdlib.h>
26#include <sys/time.h>
27#include <sys/resource.h>
28#include "busybox.h"
29
30
31extern int renice_main(int argc, char **argv)
32{
33 int prio, status = EXIT_SUCCESS;
34
35 if (argc < 3) bb_show_usage();
36
37 prio = atoi(*++argv);
38 if (prio > 20) prio = 20;
39 if (prio < -20) prio = -20;
40
41 while (*++argv) {
42 int ps = atoi(*argv);
43 int oldp = getpriority(PRIO_PROCESS, ps);
44
45 if (setpriority(PRIO_PROCESS, ps, prio) == 0) {
46 printf("%d: old priority %d, new priority %d\n", ps, oldp, prio );
47 } else {
48 bb_perror_msg("%d: setpriority", ps);
49 status = EXIT_FAILURE;
50 }
51 }
52
53 return status;
54}
diff --git a/busybox/procps/sysctl.c b/busybox/procps/sysctl.c
new file mode 100644
index 000000000..359dcc041
--- /dev/null
+++ b/busybox/procps/sysctl.c
@@ -0,0 +1,352 @@
1
2/*
3 * Sysctl 1.01 - A utility to read and manipulate the sysctl parameters
4 *
5 *
6 * "Copyright 1999 George Staikos
7 * This file may be used subject to the terms and conditions of the
8 * GNU General Public License Version 2, or any later version
9 * at your option, as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details."
14 *
15 * Changelog:
16 * v1.01:
17 * - added -p <preload> to preload values from a file
18 * v1.01.1
19 * - busybox applet aware by <solar@gentoo.org>
20 *
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include <sys/stat.h>
27#include <sys/types.h>
28#include <dirent.h>
29#include <string.h>
30#include <errno.h>
31#include <fcntl.h>
32#include "busybox.h"
33
34/*
35 * Function Prototypes
36 */
37static int sysctl_read_setting(const char *setting, int output);
38static int sysctl_write_setting(const char *setting, int output);
39static int sysctl_preload_file(const char *filename, int output);
40static int sysctl_display_all(const char *path, int output, int show_table);
41
42/*
43 * Globals...
44 */
45static const char PROC_PATH[] = "/proc/sys/";
46static const char DEFAULT_PRELOAD[] = "/etc/sysctl.conf";
47
48/* error messages */
49static const char ERR_UNKNOWN_PARAMETER[] = "error: Unknown parameter '%s'\n";
50static const char ERR_MALFORMED_SETTING[] = "error: Malformed setting '%s'\n";
51static const char ERR_NO_EQUALS[] =
52 "error: '%s' must be of the form name=value\n";
53static const char ERR_INVALID_KEY[] = "error: '%s' is an unknown key\n";
54static const char ERR_UNKNOWN_WRITING[] =
55 "error: unknown error %d setting key '%s'\n";
56static const char ERR_UNKNOWN_READING[] =
57 "error: unknown error %d reading key '%s'\n";
58static const char ERR_PERMISSION_DENIED[] =
59 "error: permission denied on key '%s'\n";
60static const char ERR_OPENING_DIR[] = "error: unable to open directory '%s'\n";
61static const char ERR_PRELOAD_FILE[] =
62 "error: unable to open preload file '%s'\n";
63static const char WARN_BAD_LINE[] =
64 "warning: %s(%d): invalid syntax, continuing...\n";
65
66
67static void dwrite_str(int fd, const char *buf)
68{
69 write(fd, buf, strlen(buf));
70}
71
72/*
73 * sysctl_main()...
74 */
75int sysctl_main(int argc, char **argv)
76{
77 int retval = 0;
78 int output = 1;
79 int write_mode = 0;
80 int switches_allowed = 1;
81
82 if (argc < 2)
83 bb_show_usage();
84
85 argv++;
86
87 for (; argv && *argv && **argv; argv++) {
88 if (switches_allowed && **argv == '-') { /* we have a switch */
89 switch ((*argv)[1]) {
90 case 'n':
91 output = 0;
92 break;
93 case 'w':
94 write_mode = 1;
95 switches_allowed = 0;
96 break;
97 case 'p':
98 argv++;
99 return
100 sysctl_preload_file(((argv && *argv
101 && **argv) ? *argv :
102 DEFAULT_PRELOAD), output);
103 case 'a':
104 case 'A':
105 switches_allowed = 0;
106 return sysctl_display_all(PROC_PATH, output,
107 ((*argv)[1] == 'a') ? 0 : 1);
108 case 'h':
109 case '?':
110 bb_show_usage();
111 default:
112 bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv);
113 bb_show_usage();
114 }
115 } else {
116 switches_allowed = 0;
117 if (write_mode)
118 retval = sysctl_write_setting(*argv, output);
119 else
120 sysctl_read_setting(*argv, output);
121 }
122 }
123 return retval;
124} /* end sysctl_main() */
125
126
127
128/*
129 * sysctl_preload_file
130 * preload the sysctl's from a conf file
131 * - we parse the file and then reform it (strip out whitespace)
132 */
133#define PRELOAD_BUF 256
134
135int sysctl_preload_file(const char *filename, int output)
136{
137 int lineno = 0;
138 char oneline[PRELOAD_BUF];
139 char buffer[PRELOAD_BUF];
140 char *name, *value, *ptr;
141 FILE *fp = NULL;
142
143 if (!filename || ((fp = fopen(filename, "r")) == NULL)) {
144 bb_error_msg_and_die(ERR_PRELOAD_FILE, filename);
145 }
146
147 while (fgets(oneline, sizeof(oneline) - 1, fp)) {
148 oneline[sizeof(oneline) - 1] = 0;
149 lineno++;
150 trim(oneline);
151 ptr = (char *) oneline;
152
153 if (*ptr == '#' || *ptr == ';')
154 continue;
155
156 if (bb_strlen(ptr) < 2)
157 continue;
158
159 name = strtok(ptr, "=");
160 if (!name || !*name) {
161 bb_error_msg(WARN_BAD_LINE, filename, lineno);
162 continue;
163 }
164
165 trim(name);
166
167 value = strtok(NULL, "\n\r");
168 if (!value || !*value) {
169 bb_error_msg(WARN_BAD_LINE, filename, lineno);
170 continue;
171 }
172
173 while ((*value == ' ' || *value == '\t') && *value != 0)
174 value++;
175 strcpy(buffer, name);
176 strcat(buffer, "=");
177 strcat(buffer, value);
178 sysctl_write_setting(buffer, output);
179 }
180 fclose(fp);
181 return 0;
182} /* end sysctl_preload_file() */
183
184
185/*
186 * Write a single sysctl setting
187 */
188int sysctl_write_setting(const char *setting, int output)
189{
190 int retval = 0;
191 const char *name = setting;
192 const char *value;
193 const char *equals;
194 char *tmpname, *outname, *cptr;
195 int fd = -1;
196
197 if (!name) /* probably dont' want to display this err */
198 return 0;
199
200 if (!(equals = strchr(setting, '='))) {
201 bb_error_msg(ERR_NO_EQUALS, setting);
202 return -1;
203 }
204
205 value = equals + sizeof(char); /* point to the value in name=value */
206
207 if (!*name || !*value || name == equals) {
208 bb_error_msg(ERR_MALFORMED_SETTING, setting);
209 return -2;
210 }
211
212 bb_xasprintf(&tmpname, "%s%.*s", PROC_PATH, (equals - name), name);
213 outname = bb_xstrdup(tmpname + strlen(PROC_PATH));
214
215 while ((cptr = strchr(tmpname, '.')) != NULL)
216 *cptr = '/';
217
218 while ((cptr = strchr(outname, '/')) != NULL)
219 *cptr = '.';
220
221 if ((fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
222 switch (errno) {
223 case ENOENT:
224 bb_error_msg(ERR_INVALID_KEY, outname);
225 break;
226 case EACCES:
227 bb_perror_msg(ERR_PERMISSION_DENIED, outname);
228 break;
229 default:
230 bb_error_msg(ERR_UNKNOWN_WRITING, errno, outname);
231 break;
232 }
233 retval = -1;
234 } else {
235 dwrite_str(fd, value);
236 close(fd);
237 if (output) {
238 dwrite_str(STDOUT_FILENO, outname);
239 dwrite_str(STDOUT_FILENO, " = ");
240 }
241 dwrite_str(STDOUT_FILENO, value);
242 dwrite_str(STDOUT_FILENO, "\n");
243 }
244
245 /* cleanup */
246 free(tmpname);
247 free(outname);
248 return retval;
249} /* end sysctl_write_setting() */
250
251
252/*
253 * Read a sysctl setting
254 *
255 */
256int sysctl_read_setting(const char *setting, int output)
257{
258 int retval = 0;
259 char *tmpname, *outname, *cptr;
260 char inbuf[1025];
261 const char *name = setting;
262 FILE *fp;
263
264 if (!setting || !*setting)
265 bb_error_msg(ERR_INVALID_KEY, setting);
266
267 tmpname = concat_path_file(PROC_PATH, name);
268 outname = bb_xstrdup(tmpname + strlen(PROC_PATH));
269
270 while ((cptr = strchr(tmpname, '.')) != NULL)
271 *cptr = '/';
272 while ((cptr = strchr(outname, '/')) != NULL)
273 *cptr = '.';
274
275 if ((fp = fopen(tmpname, "r")) == NULL) {
276 switch (errno) {
277 case ENOENT:
278 bb_error_msg(ERR_INVALID_KEY, outname);
279 break;
280 case EACCES:
281 bb_error_msg(ERR_PERMISSION_DENIED, outname);
282 break;
283 default:
284 bb_error_msg(ERR_UNKNOWN_READING, errno, outname);
285 break;
286 }
287 retval = -1;
288 } else {
289 while (fgets(inbuf, sizeof(inbuf) - 1, fp)) {
290 if (output) {
291 dwrite_str(STDOUT_FILENO, outname);
292 dwrite_str(STDOUT_FILENO, " = ");
293 }
294 dwrite_str(STDOUT_FILENO, inbuf);
295 }
296 fclose(fp);
297 }
298
299 free(tmpname);
300 free(outname);
301 return retval;
302} /* end sysctl_read_setting() */
303
304
305
306/*
307 * Display all the sysctl settings
308 *
309 */
310int sysctl_display_all(const char *path, int output, int show_table)
311{
312 int retval = 0;
313 int retval2;
314 DIR *dp;
315 struct dirent *de;
316 char *tmpdir;
317 struct stat ts;
318
319 if (!(dp = opendir(path))) {
320 bb_perror_msg(ERR_OPENING_DIR, path);
321 retval = -1;
322 } else {
323 while ((de = readdir(dp)) != NULL) {
324 tmpdir = concat_subpath_file(path, de->d_name);
325 if(tmpdir == NULL)
326 continue;
327 if ((retval2 = stat(tmpdir, &ts)) != 0)
328 bb_perror_msg(tmpdir);
329 else {
330 if (S_ISDIR(ts.st_mode)) {
331 sysctl_display_all(tmpdir, output, show_table);
332 } else
333 retval |=
334 sysctl_read_setting(tmpdir + bb_strlen(PROC_PATH),
335 output);
336
337 }
338 free(tmpdir);
339 } /* end while */
340 closedir(dp);
341 }
342
343 return retval;
344} /* end sysctl_display_all() */
345
346#ifdef STANDALONE_SYSCTL
347int main(int argc, char **argv)
348{
349 return sysctl_main(argc, argv);
350}
351const char *bb_applet_name = "sysctl";
352#endif
diff --git a/busybox/procps/top.c b/busybox/procps/top.c
new file mode 100644
index 000000000..5963c3554
--- /dev/null
+++ b/busybox/procps/top.c
@@ -0,0 +1,592 @@
1/*
2 * A tiny 'top' utility.
3 *
4 * This is written specifically for the linux /proc/<PID>/stat(m)
5 * files format.
6
7 * This reads the PIDs of all processes and their status and shows
8 * the status of processes (first ones that fit to screen) at given
9 * intervals.
10 *
11 * NOTES:
12 * - At startup this changes to /proc, all the reads are then
13 * relative to that.
14 *
15 * (C) Eero Tamminen <oak at welho dot com>
16 *
17 * Rewritten by Vladimir Oleynik (C) 2002 <dzo@simtreas.ru>
18 */
19
20/* Original code Copyrights */
21/*
22 * Copyright (c) 1992 Branko Lankester
23 * Copyright (c) 1992 Roger Binns
24 * Copyright (C) 1994-1996 Charles L. Blake.
25 * Copyright (C) 1992-1998 Michael K. Johnson
26 * May be distributed under the conditions of the
27 * GNU Library General Public License
28 */
29
30#include <sys/types.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <string.h>
35#include <sys/ioctl.h>
36/* get page info */
37#include <asm/page.h>
38#include "busybox.h"
39
40//#define FEATURE_CPU_USAGE_PERCENTAGE /* + 2k */
41
42#ifdef FEATURE_CPU_USAGE_PERCENTAGE
43#include <time.h>
44#include <sys/time.h>
45#include <fcntl.h>
46#include <netinet/in.h> /* htons */
47#endif
48
49
50typedef int (*cmp_t)(procps_status_t *P, procps_status_t *Q);
51
52static procps_status_t *top; /* Hehe */
53static int ntop;
54
55
56static int pid_sort (procps_status_t *P, procps_status_t *Q)
57{
58 return (Q->pid - P->pid);
59}
60
61static int mem_sort (procps_status_t *P, procps_status_t *Q)
62{
63 return (int)(Q->rss - P->rss);
64}
65
66#ifdef FEATURE_CPU_USAGE_PERCENTAGE
67
68#define sort_depth 3
69static cmp_t sort_function[sort_depth];
70
71static int pcpu_sort (procps_status_t *P, procps_status_t *Q)
72{
73 return (Q->pcpu - P->pcpu);
74}
75
76static int time_sort (procps_status_t *P, procps_status_t *Q)
77{
78 return (int)((Q->stime + Q->utime) - (P->stime + P->utime));
79}
80
81int mult_lvl_cmp(void* a, void* b) {
82 int i, cmp_val;
83
84 for(i = 0; i < sort_depth; i++) {
85 cmp_val = (*sort_function[i])(a, b);
86 if (cmp_val != 0)
87 return cmp_val;
88 }
89 return 0;
90}
91
92/* This structure stores some critical information from one frame to
93 the next. mostly used for sorting. Added cumulative and resident fields. */
94struct save_hist {
95 int ticks;
96 int pid;
97 int utime;
98 int stime;
99};
100
101/*
102 * Calculates percent cpu usage for each task.
103 */
104
105static struct save_hist *save_history;
106
107static unsigned long Hertz;
108
109/***********************************************************************
110 * Some values in /proc are expressed in units of 1/HZ seconds, where HZ
111 * is the kernel clock tick rate. One of these units is called a jiffy.
112 * The HZ value used in the kernel may vary according to hacker desire.
113 * According to Linus Torvalds, this is not true. He considers the values
114 * in /proc as being in architecture-dependent units that have no relation
115 * to the kernel clock tick rate. Examination of the kernel source code
116 * reveals that opinion as wishful thinking.
117 *
118 * In any case, we need the HZ constant as used in /proc. (the real HZ value
119 * may differ, but we don't care) There are several ways we could get HZ:
120 *
121 * 1. Include the kernel header file. If it changes, recompile this library.
122 * 2. Use the sysconf() function. When HZ changes, recompile the C library!
123 * 3. Ask the kernel. This is obviously correct...
124 *
125 * Linus Torvalds won't let us ask the kernel, because he thinks we should
126 * not know the HZ value. Oh well, we don't have to listen to him.
127 * Someone smuggled out the HZ value. :-)
128 *
129 * This code should work fine, even if Linus fixes the kernel to match his
130 * stated behavior. The code only fails in case of a partial conversion.
131 *
132 */
133
134#define FILE_TO_BUF(filename, fd) do{ \
135 if (fd == -1 && (fd = open(filename, O_RDONLY)) == -1) { \
136 bb_perror_msg_and_die("/proc not be mounted?"); \
137 } \
138 lseek(fd, 0L, SEEK_SET); \
139 if ((local_n = read(fd, buf, sizeof buf - 1)) < 0) { \
140 bb_perror_msg_and_die("%s", filename); \
141 } \
142 buf[local_n] = '\0'; \
143}while(0)
144
145#define FILE_TO_BUF2(filename, fd) do{ \
146 lseek(fd, 0L, SEEK_SET); \
147 if ((local_n = read(fd, buf, sizeof buf - 1)) < 0) { \
148 bb_perror_msg_and_die("%s", filename); \
149 } \
150 buf[local_n] = '\0'; \
151}while(0)
152
153static void init_Hertz_value(void) {
154 unsigned long user_j, nice_j, sys_j, other_j; /* jiffies (clock ticks) */
155 double up_1, up_2, seconds;
156 unsigned long jiffies, h;
157 char buf[80];
158 int uptime_fd = -1;
159 int stat_fd = -1;
160
161 long smp_num_cpus = sysconf(_SC_NPROCESSORS_CONF);
162
163 if(smp_num_cpus<1) smp_num_cpus=1;
164 do {
165 int local_n;
166
167 FILE_TO_BUF("uptime", uptime_fd);
168 up_1 = strtod(buf, 0);
169 FILE_TO_BUF("stat", stat_fd);
170 sscanf(buf, "cpu %lu %lu %lu %lu", &user_j, &nice_j, &sys_j, &other_j);
171 FILE_TO_BUF2("uptime", uptime_fd);
172 up_2 = strtod(buf, 0);
173 } while((long)( (up_2-up_1)*1000.0/up_1 )); /* want under 0.1% error */
174
175 close(uptime_fd);
176 close(stat_fd);
177
178 jiffies = user_j + nice_j + sys_j + other_j;
179 seconds = (up_1 + up_2) / 2;
180 h = (unsigned long)( (double)jiffies/seconds/smp_num_cpus );
181 /* actual values used by 2.4 kernels: 32 64 100 128 1000 1024 1200 */
182 switch(h){
183 case 30 ... 34 : Hertz = 32; break; /* ia64 emulator */
184 case 48 ... 52 : Hertz = 50; break;
185 case 58 ... 62 : Hertz = 60; break;
186 case 63 ... 65 : Hertz = 64; break; /* StrongARM /Shark */
187 case 95 ... 105 : Hertz = 100; break; /* normal Linux */
188 case 124 ... 132 : Hertz = 128; break; /* MIPS, ARM */
189 case 195 ... 204 : Hertz = 200; break; /* normal << 1 */
190 case 253 ... 260 : Hertz = 256; break;
191 case 295 ... 304 : Hertz = 300; break; /* 3 cpus */
192 case 393 ... 408 : Hertz = 400; break; /* normal << 2 */
193 case 495 ... 504 : Hertz = 500; break; /* 5 cpus */
194 case 595 ... 604 : Hertz = 600; break; /* 6 cpus */
195 case 695 ... 704 : Hertz = 700; break; /* 7 cpus */
196 case 790 ... 808 : Hertz = 800; break; /* normal << 3 */
197 case 895 ... 904 : Hertz = 900; break; /* 9 cpus */
198 case 990 ... 1010 : Hertz = 1000; break; /* ARM */
199 case 1015 ... 1035 : Hertz = 1024; break; /* Alpha, ia64 */
200 case 1095 ... 1104 : Hertz = 1100; break; /* 11 cpus */
201 case 1180 ... 1220 : Hertz = 1200; break; /* Alpha */
202 default:
203 /* If 32-bit or big-endian (not Alpha or ia64), assume HZ is 100. */
204 Hertz = (sizeof(long)==sizeof(int) || htons(999)==999) ? 100UL : 1024UL;
205 }
206}
207
208static void do_stats(void)
209{
210 struct timeval t;
211 static struct timeval oldtime;
212 struct timezone timez;
213 float elapsed_time;
214
215 procps_status_t *cur;
216 int total_time, i, n;
217 static int prev_count;
218 int systime, usrtime, pid;
219
220 struct save_hist *New_save_hist;
221
222 /*
223 * Finds the current time (in microseconds) and calculates the time
224 * elapsed since the last update.
225 */
226 gettimeofday(&t, &timez);
227 elapsed_time = (t.tv_sec - oldtime.tv_sec)
228 + (float) (t.tv_usec - oldtime.tv_usec) / 1000000.0;
229 oldtime.tv_sec = t.tv_sec;
230 oldtime.tv_usec = t.tv_usec;
231
232 New_save_hist = alloca(sizeof(struct save_hist)*ntop);
233 /*
234 * Make a pass through the data to get stats.
235 */
236 for(n = 0; n < ntop; n++) {
237 cur = top + n;
238
239 /*
240 * Calculate time in cur process. Time is sum of user time
241 * (usrtime) plus system time (systime).
242 */
243 systime = cur->stime;
244 usrtime = cur->utime;
245 pid = cur->pid;
246 total_time = systime + usrtime;
247 New_save_hist[n].ticks = total_time;
248 New_save_hist[n].pid = pid;
249 New_save_hist[n].stime = systime;
250 New_save_hist[n].utime = usrtime;
251
252 /* find matching entry from previous pass */
253 for (i = 0; i < prev_count; i++) {
254 if (save_history[i].pid == pid) {
255 total_time -= save_history[i].ticks;
256 systime -= save_history[i].stime;
257 usrtime -= save_history[i].utime;
258 break;
259 }
260 }
261
262 /*
263 * Calculate percent cpu time for cur task.
264 */
265 i = (total_time * 10 * 100/Hertz) / elapsed_time;
266 if (i > 999)
267 i = 999;
268 cur->pcpu = i;
269
270 }
271
272 /*
273 * Save cur frame's information.
274 */
275 free(save_history);
276 save_history = memcpy(xmalloc(sizeof(struct save_hist)*n), New_save_hist,
277 sizeof(struct save_hist)*n);
278 prev_count = n;
279 qsort(top, n, sizeof(procps_status_t), (void*)mult_lvl_cmp);
280}
281#else
282static cmp_t sort_function;
283#endif /* FEATURE_CPU_USAGE_PERCENTAGE */
284
285/* display generic info (meminfo / loadavg) */
286static unsigned long display_generic(void)
287{
288 FILE *fp;
289 char buf[80];
290 float avg1, avg2, avg3;
291 unsigned long total, used, mfree, shared, buffers, cached;
292 unsigned int needs_conversion = 1;
293
294 /* read memory info */
295 fp = bb_xfopen("meminfo", "r");
296
297 /*
298 * Old kernels (such as 2.4.x) had a nice summary of memory info that
299 * we could parse, however this is gone entirely in 2.6. Try parsing
300 * the old way first, and if that fails, parse each field manually.
301 *
302 * First, we read in the first line. Old kernels will have bogus
303 * strings we don't care about, whereas new kernels will start right
304 * out with MemTotal:
305 * -- PFM.
306 */
307 if (fscanf(fp, "MemTotal: %lu %s\n", &total, buf) != 2) {
308 fgets(buf, sizeof(buf), fp); /* skip first line */
309
310 fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu",
311 &total, &used, &mfree, &shared, &buffers, &cached);
312 } else {
313 /*
314 * Revert to manual parsing, which incidentally already has the
315 * sizes in kilobytes. This should be safe for both 2.4 and
316 * 2.6.
317 */
318 needs_conversion = 0;
319
320 fscanf(fp, "MemFree: %lu %s\n", &mfree, buf);
321
322 /*
323 * MemShared: is no longer present in 2.6. Report this as 0,
324 * to maintain consistent behavior with normal procps.
325 */
326 if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2)
327 shared = 0;
328
329 fscanf(fp, "Buffers: %lu %s\n", &buffers, buf);
330 fscanf(fp, "Cached: %lu %s\n", &cached, buf);
331
332 used = total - mfree;
333 }
334 fclose(fp);
335
336 /* read load average */
337 fp = bb_xfopen("loadavg", "r");
338 if (fscanf(fp, "%f %f %f", &avg1, &avg2, &avg3) != 3) {
339 bb_error_msg_and_die("failed to read '%s'", "loadavg");
340 }
341 fclose(fp);
342
343 if (needs_conversion) {
344 /* convert to kilobytes */
345 used /= 1024;
346 mfree /= 1024;
347 shared /= 1024;
348 buffers /= 1024;
349 cached /= 1024;
350 total /= 1024;
351 }
352
353 /* output memory info and load average */
354 /* clear screen & go to top */
355 printf("\e[H\e[J" "Mem: "
356 "%ldK used, %ldK free, %ldK shrd, %ldK buff, %ldK cached\n",
357 used, mfree, shared, buffers, cached);
358 printf("Load average: %.2f, %.2f, %.2f "
359 "(State: S=sleeping R=running, W=waiting)\n",
360 avg1, avg2, avg3);
361 return total;
362}
363
364
365/* display process statuses */
366static void display_status(int count, int col)
367{
368 procps_status_t *s = top;
369 char rss_str_buf[8];
370 unsigned long total_memory = display_generic();
371
372#ifdef FEATURE_CPU_USAGE_PERCENTAGE
373 /* what info of the processes is shown */
374 printf("\n\e[7m PID USER STATUS RSS PPID %%CPU %%MEM COMMAND\e[0m\n");
375#else
376 printf("\n\e[7m PID USER STATUS RSS PPID %%MEM COMMAND\e[0m\n");
377#endif
378
379 while (count--) {
380 char *namecmd = s->short_cmd;
381 int pmem;
382
383 pmem = 1000.0 * s->rss / total_memory;
384 if (pmem > 999) pmem = 999;
385
386 if(s->rss > 10*1024)
387 sprintf(rss_str_buf, "%6ldM", s->rss/1024);
388 else
389 sprintf(rss_str_buf, "%7ld", s->rss);
390#ifdef FEATURE_CPU_USAGE_PERCENTAGE
391 printf("%5d %-8s %s %s %5d %2d.%d %2u.%u ",
392 s->pid, s->user, s->state, rss_str_buf, s->ppid,
393 s->pcpu/10, s->pcpu%10, pmem/10, pmem%10);
394#else
395 printf("%5d %-8s %s %s %5d %2u.%u ",
396 s->pid, s->user, s->state, rss_str_buf, s->ppid,
397 pmem/10, pmem%10);
398#endif
399 if(strlen(namecmd) > col)
400 namecmd[col] = 0;
401 printf("%s\n", namecmd);
402 s++;
403 }
404}
405
406static void clearmems(void)
407{
408 free(top);
409 top = 0;
410 ntop = 0;
411}
412
413#if defined CONFIG_FEATURE_USE_TERMIOS
414#include <termios.h>
415#include <sys/time.h>
416#include <signal.h>
417
418
419static struct termios initial_settings;
420
421static void reset_term(void)
422{
423 tcsetattr(0, TCSANOW, (void *) &initial_settings);
424#ifdef CONFIG_FEATURE_CLEAN_UP
425 clearmems();
426#ifdef FEATURE_CPU_USAGE_PERCENTAGE
427 free(save_history);
428#endif
429#endif /* CONFIG_FEATURE_CLEAN_UP */
430}
431
432static void sig_catcher (int sig)
433{
434 reset_term();
435}
436#endif /* CONFIG_FEATURE_USE_TERMIOS */
437
438
439int top_main(int argc, char **argv)
440{
441 int opt, interval, lines, col;
442#if defined CONFIG_FEATURE_USE_TERMIOS
443 struct termios new_settings;
444 struct timeval tv;
445 fd_set readfds;
446 unsigned char c;
447 struct sigaction sa;
448#endif /* CONFIG_FEATURE_USE_TERMIOS */
449
450 /* Default update rate is 5 seconds */
451 interval = 5;
452
453 /* do normal option parsing */
454 while ((opt = getopt(argc, argv, "d:")) > 0) {
455 switch (opt) {
456 case 'd':
457 interval = atoi(optarg);
458 break;
459 default:
460 bb_show_usage();
461 }
462 }
463
464 /* Default to 25 lines - 5 lines for status */
465 lines = 25 - 5;
466 /* Default CMD format size */
467#ifdef FEATURE_CPU_USAGE_PERCENTAGE
468 col = 35 - 6;
469#else
470 col = 35;
471#endif
472 /* change to /proc */
473 if (chdir("/proc") < 0) {
474 bb_perror_msg_and_die("chdir('/proc')");
475 }
476#if defined CONFIG_FEATURE_USE_TERMIOS
477 tcgetattr(0, (void *) &initial_settings);
478 memcpy(&new_settings, &initial_settings, sizeof(struct termios));
479 new_settings.c_lflag &= ~(ISIG | ICANON); /* unbuffered input */
480 /* Turn off echoing */
481 new_settings.c_lflag &= ~(ECHO | ECHONL);
482
483 signal (SIGTERM, sig_catcher);
484 sigaction (SIGTERM, (struct sigaction *) 0, &sa);
485 sa.sa_flags |= SA_RESTART;
486 sa.sa_flags &= ~SA_INTERRUPT;
487 sigaction (SIGTERM, &sa, (struct sigaction *) 0);
488 sigaction (SIGINT, &sa, (struct sigaction *) 0);
489 tcsetattr(0, TCSANOW, (void *) &new_settings);
490 atexit(reset_term);
491
492 get_terminal_width_height(0, &col, &lines);
493 if (lines > 4) {
494 lines -= 5;
495#ifdef FEATURE_CPU_USAGE_PERCENTAGE
496 col = col - 80 + 35 - 6;
497#else
498 col = col - 80 + 35;
499#endif
500 }
501#endif /* CONFIG_FEATURE_USE_TERMIOS */
502#ifdef FEATURE_CPU_USAGE_PERCENTAGE
503 sort_function[0] = pcpu_sort;
504 sort_function[1] = mem_sort;
505 sort_function[2] = time_sort;
506#else
507 sort_function = mem_sort;
508#endif
509 while (1) {
510 /* read process IDs & status for all the processes */
511 procps_status_t * p;
512
513#ifdef CONFIG_SELINUX
514 while ((p = procps_scan(0, 0, NULL) ) != 0) {
515#else
516 while ((p = procps_scan(0)) != 0) {
517#endif
518 int n = ntop;
519
520 top = xrealloc(top, (++ntop)*sizeof(procps_status_t));
521 memcpy(top + n, p, sizeof(procps_status_t));
522 }
523 if (ntop == 0) {
524 bb_perror_msg_and_die("scandir('/proc')");
525 }
526#ifdef FEATURE_CPU_USAGE_PERCENTAGE
527 if(!Hertz) {
528 init_Hertz_value();
529 do_stats();
530 sleep(1);
531 clearmems();
532 continue;
533 }
534 do_stats();
535#else
536 qsort(top, ntop, sizeof(procps_status_t), (void*)sort_function);
537#endif
538 opt = lines;
539 if (opt > ntop) {
540 opt = ntop;
541 }
542 /* show status for each of the processes */
543 display_status(opt, col);
544#if defined CONFIG_FEATURE_USE_TERMIOS
545 tv.tv_sec = interval;
546 tv.tv_usec = 0;
547 FD_ZERO (&readfds);
548 FD_SET (0, &readfds);
549 select (1, &readfds, NULL, NULL, &tv);
550 if (FD_ISSET (0, &readfds)) {
551 if (read (0, &c, 1) <= 0) { /* signal */
552 return EXIT_FAILURE;
553 }
554 if(c == 'q' || c == initial_settings.c_cc[VINTR])
555 return EXIT_SUCCESS;
556 if(c == 'M') {
557#ifdef FEATURE_CPU_USAGE_PERCENTAGE
558 sort_function[0] = mem_sort;
559 sort_function[1] = pcpu_sort;
560 sort_function[2] = time_sort;
561#else
562 sort_function = mem_sort;
563#endif
564 }
565#ifdef FEATURE_CPU_USAGE_PERCENTAGE
566 if(c == 'P') {
567 sort_function[0] = pcpu_sort;
568 sort_function[1] = mem_sort;
569 sort_function[2] = time_sort;
570 }
571 if(c == 'T') {
572 sort_function[0] = time_sort;
573 sort_function[1] = mem_sort;
574 sort_function[2] = pcpu_sort;
575 }
576#endif
577 if(c == 'N') {
578#ifdef FEATURE_CPU_USAGE_PERCENTAGE
579 sort_function[0] = pid_sort;
580#else
581 sort_function = pid_sort;
582#endif
583 }
584 }
585#else
586 sleep(interval);
587#endif /* CONFIG_FEATURE_USE_TERMIOS */
588 clearmems();
589 }
590
591 return EXIT_SUCCESS;
592}
diff --git a/busybox/procps/uptime.c b/busybox/procps/uptime.c
new file mode 100644
index 000000000..38d58af9c
--- /dev/null
+++ b/busybox/procps/uptime.c
@@ -0,0 +1,75 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini uptime implementation for busybox
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23/* This version of uptime doesn't display the number of users on the system,
24 * since busybox init doesn't mess with utmp. For folks using utmp that are
25 * just dying to have # of users reported, feel free to write it as some type
26 * of CONFIG_FEATURE_UTMP_SUPPORT #define
27 */
28
29/* getopt not needed */
30
31
32#include <stdio.h>
33#include <time.h>
34#include <errno.h>
35#include <stdlib.h>
36#include "busybox.h"
37
38static const int FSHIFT = 16; /* nr of bits of precision */
39#define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */
40#define LOAD_INT(x) ((x) >> FSHIFT)
41#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
42
43
44extern int uptime_main(int argc, char **argv)
45{
46 int updays, uphours, upminutes;
47 struct sysinfo info;
48 struct tm *current_time;
49 time_t current_secs;
50
51 time(&current_secs);
52 current_time = localtime(&current_secs);
53
54 sysinfo(&info);
55
56 printf(" %02d:%02d:%02d up ",
57 current_time->tm_hour, current_time->tm_min, current_time->tm_sec);
58 updays = (int) info.uptime / (60*60*24);
59 if (updays)
60 printf("%d day%s, ", updays, (updays != 1) ? "s" : "");
61 upminutes = (int) info.uptime / 60;
62 uphours = (upminutes / 60) % 24;
63 upminutes %= 60;
64 if(uphours)
65 printf("%2d:%02d, ", uphours, upminutes);
66 else
67 printf("%d min, ", upminutes);
68
69 printf("load average: %ld.%02ld, %ld.%02ld, %ld.%02ld\n",
70 LOAD_INT(info.loads[0]), LOAD_FRAC(info.loads[0]),
71 LOAD_INT(info.loads[1]), LOAD_FRAC(info.loads[1]),
72 LOAD_INT(info.loads[2]), LOAD_FRAC(info.loads[2]));
73
74 return EXIT_SUCCESS;
75}