diff options
Diffstat (limited to 'ps.c')
-rw-r--r-- | ps.c | 266 |
1 files changed, 0 insertions, 266 deletions
@@ -1,266 +0,0 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Mini ps implementation(s) for busybox | ||
4 | * | ||
5 | * Copyright (C) 1999,2000,2001 by Lineo, inc. | ||
6 | * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> | ||
7 | * | ||
8 | * | ||
9 | * This contains _two_ implementations of ps for Linux. One uses the | ||
10 | * traditional /proc virtual filesystem, and the other use the devps kernel | ||
11 | * driver (written by Erik Andersen to avoid using /proc thereby saving 100k+). | ||
12 | * | ||
13 | * | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify it | ||
16 | * under the terms of the GNU General Public License as published by the Free | ||
17 | * Software Foundation; either version 2 of the License, or (at your option) | ||
18 | * any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
21 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
22 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
23 | * more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License along with | ||
26 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
27 | * Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <stdio.h> | ||
32 | #include <stdlib.h> | ||
33 | #include <unistd.h> | ||
34 | #include <dirent.h> | ||
35 | #include <errno.h> | ||
36 | #include <fcntl.h> | ||
37 | #include <ctype.h> | ||
38 | #include <string.h> | ||
39 | #include <termios.h> | ||
40 | #include <sys/ioctl.h> | ||
41 | #include "busybox.h" | ||
42 | |||
43 | static const int TERMINAL_WIDTH = 79; /* not 80 in case terminal has linefold bug */ | ||
44 | |||
45 | |||
46 | |||
47 | #if ! defined BB_FEATURE_USE_DEVPS_PATCH | ||
48 | |||
49 | /* The following is the first ps implementation -- | ||
50 | * the one using the /proc virtual filesystem. | ||
51 | */ | ||
52 | |||
53 | typedef struct proc_s { | ||
54 | char | ||
55 | cmd[16]; /* basename of executable file in call to exec(2) */ | ||
56 | int | ||
57 | ruid, /* real only (sorry) */ | ||
58 | pid, /* process id */ | ||
59 | ppid; /* pid of parent process */ | ||
60 | char | ||
61 | state; /* single-char code for process state (S=sleeping) */ | ||
62 | } proc_t; | ||
63 | |||
64 | |||
65 | |||
66 | static int file2str(char *filename, char *ret, int cap) | ||
67 | { | ||
68 | int fd, num_read; | ||
69 | |||
70 | if ((fd = open(filename, O_RDONLY, 0)) == -1) | ||
71 | return -1; | ||
72 | if ((num_read = read(fd, ret, cap - 1)) <= 0) | ||
73 | return -1; | ||
74 | ret[num_read] = 0; | ||
75 | close(fd); | ||
76 | return num_read; | ||
77 | } | ||
78 | |||
79 | |||
80 | static void parse_proc_status(char *S, proc_t * P) | ||
81 | { | ||
82 | char *tmp; | ||
83 | |||
84 | memset(P->cmd, 0, sizeof P->cmd); | ||
85 | sscanf(S, "Name:\t%15c", P->cmd); | ||
86 | tmp = strchr(P->cmd, '\n'); | ||
87 | if (tmp) | ||
88 | *tmp = '\0'; | ||
89 | tmp = strstr(S, "State"); | ||
90 | sscanf(tmp, "State:\t%c", &P->state); | ||
91 | |||
92 | tmp = strstr(S, "Pid:"); | ||
93 | if (tmp) | ||
94 | sscanf(tmp, "Pid:\t%d\n" "PPid:\t%d\n", &P->pid, &P->ppid); | ||
95 | else | ||
96 | error_msg("Internal error!"); | ||
97 | |||
98 | /* For busybox, ignoring effective, saved, etc. */ | ||
99 | tmp = strstr(S, "Uid:"); | ||
100 | if (tmp) | ||
101 | sscanf(tmp, "Uid:\t%d", &P->ruid); | ||
102 | else | ||
103 | error_msg("Internal error!"); | ||
104 | |||
105 | |||
106 | } | ||
107 | |||
108 | extern int ps_main(int argc, char **argv) | ||
109 | { | ||
110 | proc_t p; | ||
111 | DIR *dir; | ||
112 | FILE *file; | ||
113 | struct dirent *entry; | ||
114 | char path[32], sbuf[512]; | ||
115 | char uidName[9]; | ||
116 | int len, i, c; | ||
117 | #ifdef BB_FEATURE_AUTOWIDTH | ||
118 | struct winsize win = { 0, 0, 0, 0 }; | ||
119 | int terminal_width = TERMINAL_WIDTH; | ||
120 | #else | ||
121 | #define terminal_width TERMINAL_WIDTH | ||
122 | #endif | ||
123 | |||
124 | |||
125 | |||
126 | dir = opendir("/proc"); | ||
127 | if (!dir) | ||
128 | error_msg_and_die("Can't open /proc"); | ||
129 | |||
130 | #ifdef BB_FEATURE_AUTOWIDTH | ||
131 | ioctl(fileno(stdout), TIOCGWINSZ, &win); | ||
132 | if (win.ws_col > 0) | ||
133 | terminal_width = win.ws_col - 1; | ||
134 | #endif | ||
135 | |||
136 | printf(" PID Uid Stat Command\n"); | ||
137 | while ((entry = readdir(dir)) != NULL) { | ||
138 | if (!isdigit(*entry->d_name)) | ||
139 | continue; | ||
140 | sprintf(path, "/proc/%s/status", entry->d_name); | ||
141 | if ((file2str(path, sbuf, sizeof sbuf)) != -1) { | ||
142 | parse_proc_status(sbuf, &p); | ||
143 | } | ||
144 | |||
145 | /* Make some adjustments as needed */ | ||
146 | my_getpwuid(uidName, p.ruid); | ||
147 | if (*uidName == '\0') | ||
148 | sprintf(uidName, "%d", p.ruid); | ||
149 | |||
150 | sprintf(path, "/proc/%s/cmdline", entry->d_name); | ||
151 | file = fopen(path, "r"); | ||
152 | if (file == NULL) | ||
153 | continue; | ||
154 | i = 0; | ||
155 | len = printf("%5d %-8s %c ", p.pid, uidName, p.state); | ||
156 | while (((c = getc(file)) != EOF) && (i < (terminal_width-len))) { | ||
157 | i++; | ||
158 | if (c == '\0') | ||
159 | c = ' '; | ||
160 | putc(c, stdout); | ||
161 | } | ||
162 | fclose(file); | ||
163 | if (i == 0) | ||
164 | printf("[%s]", p.cmd); | ||
165 | putchar('\n'); | ||
166 | } | ||
167 | closedir(dir); | ||
168 | return EXIT_SUCCESS; | ||
169 | } | ||
170 | |||
171 | |||
172 | #else /* BB_FEATURE_USE_DEVPS_PATCH */ | ||
173 | |||
174 | |||
175 | /* The following is the second ps implementation -- | ||
176 | * this one uses the nifty new devps kernel device. | ||
177 | */ | ||
178 | |||
179 | #include <linux/devps.h> /* For Erik's nifty devps device driver */ | ||
180 | |||
181 | |||
182 | extern int ps_main(int argc, char **argv) | ||
183 | { | ||
184 | char device[] = "/dev/ps"; | ||
185 | int i, j, len, fd; | ||
186 | pid_t num_pids; | ||
187 | pid_t* pid_array = NULL; | ||
188 | struct pid_info info; | ||
189 | char uidName[9]; | ||
190 | #ifdef BB_FEATURE_AUTOWIDTH | ||
191 | struct winsize win = { 0, 0, 0, 0 }; | ||
192 | int terminal_width = TERMINAL_WIDTH; | ||
193 | #else | ||
194 | #define terminal_width TERMINAL_WIDTH | ||
195 | #endif | ||
196 | |||
197 | if (argc > 1 && **(argv + 1) == '-') | ||
198 | show_usage(); | ||
199 | |||
200 | /* open device */ | ||
201 | fd = open(device, O_RDONLY); | ||
202 | if (fd < 0) | ||
203 | perror_msg_and_die( "open failed for `%s'", device); | ||
204 | |||
205 | /* Find out how many processes there are */ | ||
206 | if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) | ||
207 | perror_msg_and_die( "\nDEVPS_GET_PID_LIST"); | ||
208 | |||
209 | /* Allocate some memory -- grab a few extras just in case | ||
210 | * some new processes start up while we wait. The kernel will | ||
211 | * just ignore any extras if we give it too many, and will trunc. | ||
212 | * the list if we give it too few. */ | ||
213 | pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t)); | ||
214 | pid_array[0] = num_pids+10; | ||
215 | |||
216 | /* Now grab the pid list */ | ||
217 | if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) | ||
218 | perror_msg_and_die("\nDEVPS_GET_PID_LIST"); | ||
219 | |||
220 | #ifdef BB_FEATURE_AUTOWIDTH | ||
221 | ioctl(fileno(stdout), TIOCGWINSZ, &win); | ||
222 | if (win.ws_col > 0) | ||
223 | terminal_width = win.ws_col - 1; | ||
224 | #endif | ||
225 | |||
226 | /* Print up a ps listing */ | ||
227 | printf(" PID Uid Stat Command\n"); | ||
228 | |||
229 | for (i=1; i<pid_array[0] ; i++) { | ||
230 | info.pid = pid_array[i]; | ||
231 | |||
232 | if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0) | ||
233 | perror_msg_and_die("\nDEVPS_GET_PID_INFO"); | ||
234 | |||
235 | /* Make some adjustments as needed */ | ||
236 | my_getpwuid(uidName, info.euid); | ||
237 | if (*uidName == '\0') | ||
238 | sprintf(uidName, "%ld", info.euid); | ||
239 | |||
240 | len = printf("%5d %-8s %c ", info.pid, uidName, info.state); | ||
241 | |||
242 | if (strlen(info.command_line) > 1) { | ||
243 | for( j=0; j<(sizeof(info.command_line)-1) && j < (terminal_width-len); j++) { | ||
244 | if (*(info.command_line+j) == '\0' && *(info.command_line+j+1) != '\0') { | ||
245 | *(info.command_line+j) = ' '; | ||
246 | } | ||
247 | } | ||
248 | *(info.command_line+j) = '\0'; | ||
249 | puts(info.command_line); | ||
250 | } else { | ||
251 | printf("[%s]\n", info.name); | ||
252 | } | ||
253 | } | ||
254 | |||
255 | /* Free memory */ | ||
256 | free( pid_array); | ||
257 | |||
258 | /* close device */ | ||
259 | if (close (fd) != 0) | ||
260 | perror_msg_and_die("close failed for `%s'", device); | ||
261 | |||
262 | exit (0); | ||
263 | } | ||
264 | |||
265 | #endif /* BB_FEATURE_USE_DEVPS_PATCH */ | ||
266 | |||