Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/procps/ps.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/procps/ps.c
r821 r1770 4 4 * 5 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> 6 8 * 7 * Licensed under the GPL v 2, see the file LICENSE in this tarball.9 * Licensed under the GPL version 2, see the file LICENSE in this tarball. 8 10 */ 9 11 10 #include "busybox.h" 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <unistd.h> 14 #include <dirent.h> 15 #include <errno.h> 16 #include <fcntl.h> 17 #include <ctype.h> 18 #include <string.h> 19 #include <termios.h> 20 #include <sys/ioctl.h> 21 #if ENABLE_SELINUX 22 #include <selinux/selinux.h> /* for is_selinux_enabled() */ 23 #endif 24 12 #include "libbb.h" 13 14 /* Absolute maximum on output line length */ 15 enum { MAX_WIDTH = 2*1024 }; 16 17 #if ENABLE_DESKTOP 18 19 /* Print value to buf, max size+1 chars (including trailing '\0') */ 20 21 static 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 26 static void func_comm(char *buf, int size, const procps_status_t *ps) 27 { 28 safe_strncpy(buf, ps->comm, size+1); 29 } 30 31 static void func_args(char *buf, int size, const procps_status_t *ps) 32 { 33 read_cmdline(buf, size, ps->pid, ps->comm); 34 } 35 36 static void func_pid(char *buf, int size, const procps_status_t *ps) 37 { 38 sprintf(buf, "%*u", size, ps->pid); 39 } 40 41 static void func_ppid(char *buf, int size, const procps_status_t *ps) 42 { 43 sprintf(buf, "%*u", size, ps->ppid); 44 } 45 46 static void func_pgid(char *buf, int size, const procps_status_t *ps) 47 { 48 sprintf(buf, "%*u", size, ps->pgid); 49 } 50 51 static 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 58 static void func_vsz(char *buf, int size, const procps_status_t *ps) 59 { 60 put_u(buf, size, ps->vsz); 61 } 62 63 static void func_rss(char *buf, int size, const procps_status_t *ps) 64 { 65 put_u(buf, size, ps->rss); 66 } 67 68 static 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 77 static 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 /* 84 static void func_nice(char *buf, int size, const procps_status_t *ps) 85 { 86 ps->??? 87 } 88 89 static void func_etime(char *buf, int size, const procps_status_t *ps) 90 { 91 elapled time [[dd-]hh:]mm:ss 92 } 93 94 static void func_time(char *buf, int size, const procps_status_t *ps) 95 { 96 cumulative time [[dd-]hh:]mm:ss 97 } 98 99 static void func_pcpu(char *buf, int size, const procps_status_t *ps) 100 { 101 } 102 */ 103 104 typedef 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 112 static 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 143 struct 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 161 static 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 168 static 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 178 static 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 217 static 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 235 static 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 257 static 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 281 int ps_main(int argc, char **argv); 25 282 int ps_main(int argc, char **argv) 26 283 { 27 procps_status_t * p; 28 int i, len; 29 30 #if ENABLE_SELINUX 31 int use_selinux = 0; 32 security_context_t sid=NULL; 33 #endif 34 35 #if ENABLE_FEATURE_PS_WIDE 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 343 int ps_main(int argc, char **argv); 344 int 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 36 353 int terminal_width; 37 354 int w_count = 0; 38 39 bb_opt_complementally="-:ww";40 #else41 # define terminal_width 7942 355 #endif 43 356 44 357 #if ENABLE_FEATURE_PS_WIDE || ENABLE_SELINUX 45 /* handle arguments */46 #if ENABLE_FEATURE_PS_WIDE && ENABLE_SELINUX47 i = bb_getopt_ulflags(argc, argv, "wc", &w_count);48 #elif ENABLE_FEATURE_PS_WIDE && !ENABLE_SELINUX49 bb_getopt_ulflags(argc, argv, "w", &w_count);50 #else /* !ENABLE_FEATURE_PS_WIDE && ENABLE_SELINUX */51 i = bb_getopt_ulflags(argc, argv, "c");52 #endif53 358 #if ENABLE_FEATURE_PS_WIDE 359 opt_complementary = "-:ww"; 360 USE_SELINUX(i =) getopt32(argv, USE_SELINUX("Z") "w", &w_count); 54 361 /* if w is given once, GNU ps sets the width to 132, 55 362 * if w is given more than once, it is "unlimited" 56 363 */ 57 if (w_count) {58 terminal_width = (w_count==1) ? 132 : INT_MAX;364 if (w_count) { 365 terminal_width = (w_count==1) ? 132 : MAX_WIDTH; 59 366 } else { 60 get_terminal_width_height( 1, &terminal_width, NULL);367 get_terminal_width_height(0, &terminal_width, NULL); 61 368 /* Go one less... */ 62 terminal_width--; 63 } 64 #endif 65 #if ENABLE_SELINUX 66 if ((i & (1+ENABLE_FEATURE_PS_WIDE)) && is_selinux_enabled()) 67 use_selinux = 1; 68 #endif 69 #endif /* ENABLE_FEATURE_PS_WIDE || ENABLE_SELINUX */ 70 71 #if ENABLE_SELINUX 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 72 381 if (use_selinux) 73 printf(" PID Context Stat Command\n");382 puts(" PID Context Stat Command"); 74 383 else 75 #endif 76 printf(" PID Uid VmSize Stat Command\n"); 77 78 while ((p = procps_scan(1)) != 0) { 79 char *namecmd = p->cmd; 80 #if ENABLE_SELINUX 81 if (use_selinux) 82 { 83 char sbuf[128]; 84 len = sizeof(sbuf); 85 86 if (is_selinux_enabled()) { 87 if (getpidcon(p->pid,&sid)<0) 88 sid=NULL; 89 } 90 91 if (sid) { 92 /* I assume sid initilized with NULL */ 93 len = strlen(sid)+1; 94 safe_strncpy(sbuf, sid, len); 95 freecon(sid); 96 sid=NULL; 97 }else { 98 safe_strncpy(sbuf, "unknown",7); 99 } 100 len = printf("%5d %-32s %s ", p->pid, sbuf, p->state); 101 } 102 else 103 #endif 104 if(p->rss == 0) 105 len = printf("%5d %-8s %s ", p->pid, p->user, p->state); 106 else 107 len = printf("%5d %-8s %6ld %s ", p->pid, p->user, p->rss, p->state); 108 109 i = terminal_width-len; 110 111 if(namecmd && namecmd[0]) { 112 if(i < 0) 113 i = 0; 114 if(strlen(namecmd) > (size_t)i) 115 namecmd[i] = 0; 116 printf("%s\n", namecmd); 117 } else { 118 namecmd = p->short_cmd; 119 if(i < 2) 120 i = 2; 121 if(strlen(namecmd) > ((size_t)i-2)) 122 namecmd[i-2] = 0; 123 printf("[%s]\n", namecmd); 124 } 125 /* no check needed, but to make valgrind happy.. */ 126 if (ENABLE_FEATURE_CLEAN_UP && p->cmd) 127 free(p->cmd); 128 } 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(); 129 421 return EXIT_SUCCESS; 130 422 } 423 424 #endif /* ENABLE_DESKTOP */
Note:
See TracChangeset
for help on using the changeset viewer.