Jens Michaelsen pointed out that Linksys' firmware download side moved.
[oweals/busybox.git] / procps / ps.c
index b8e4cd3a07664c3c0b59660bc444f74cf9559349..9dc68395ae1996117251e8d06f4431cc884a4074 100644 (file)
+/* vi: set sw=4 ts=4: */
 /*
- * Mini ps implementation for busybox
+ * Mini ps implementation(s) for busybox
  *
- * Copyright (C) 1998 by Erik Andersen <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
  *
+ * Licensed under the GPL v2, see the file LICENSE in this tarball.
  */
 
-#include "internal.h"
+#include "busybox.h"
+#include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <dirent.h>
-#include <stdio.h>
-
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#if ENABLE_SELINUX
+#include <selinux/selinux.h>  /* for is_selinux_enabled()  */
+#endif
 
-extern int ps_main(int argc, char **argv)
+int ps_main(int argc, char **argv)
 {
-    DIR *dir;
-    FILE *file;
-    struct dirent *entry;
+       procps_status_t * p;
+       int i, len;
+
+#if ENABLE_SELINUX
+       int use_selinux = 0;
+       security_context_t sid=NULL;
+#endif
+
+#if ENABLE_FEATURE_PS_WIDE
+       int terminal_width;
+       int w_count = 0;
 
-    if ( argc>1 && **(argv+1) == '-' ) {
-       usage ("ps\n");
-    }
-    
-    dir = opendir("/proc");
-    if (!dir) {
-       perror("Can't open /proc");
-       exit(FALSE);
-    }
+       bb_opt_complementally="-:ww";
+#else
+# define terminal_width 79
+#endif
 
-    fprintf(stdout, "PID\tUid\tGid\tState\tName\n");
-    while ((entry = readdir(dir)) != NULL) {
-       char psStatus[NAME_MAX];
-       char psName[NAME_MAX]="";
-       char psState[NAME_MAX]="";
-       int psPID=0, psPPID=0, psUid=0, psGid=0;
-       //if (match(entry->d_name, "[0-9]") == FALSE)
-       //    continue;
-       sprintf(psStatus, "/proc/%s/status", entry->d_name);
-       file = fopen( psStatus, "r");
-       if (file == NULL) {
-           continue;
-           //perror(psStatus);
-           //exit( FALSE);
+#if ENABLE_FEATURE_PS_WIDE || ENABLE_SELINUX
+       /* handle arguments */
+#if ENABLE_FEATURE_PS_WIDE && ENABLE_SELINUX
+       i = bb_getopt_ulflags(argc, argv, "wc", &w_count);
+#elif ENABLE_FEATURE_PS_WIDE && !ENABLE_SELINUX
+       bb_getopt_ulflags(argc, argv, "w", &w_count);
+#else /* !ENABLE_FEATURE_PS_WIDE && ENABLE_SELINUX */
+       i = bb_getopt_ulflags(argc, argv, "c");
+#endif
+#if ENABLE_FEATURE_PS_WIDE
+       /* if w is given once, GNU ps sets the width to 132,
+        * if w is given more than once, it is "unlimited"
+        */
+       if(w_count) {
+               terminal_width = (w_count==1) ? 132 : INT_MAX;
+       } else {
+               get_terminal_width_height(1, &terminal_width, NULL);
+               /* Go one less... */
+               terminal_width--;
        }
-       fscanf(file, "Name:\t%s\nState:\t%s\nPid:\t%d\nPPid:\t%d\nUid:\t%d\nGid:\t%d", 
-               psName, psState, &psPID, &psPPID, &psUid, &psGid);
-       fclose(file);
+#endif
+#if ENABLE_SELINUX
+       if ((i & (1+ENABLE_FEATURE_PS_WIDE)) && is_selinux_enabled())
+               use_selinux = 1;
+#endif
+#endif  /* ENABLE_FEATURE_PS_WIDE || ENABLE_SELINUX */
 
-       fprintf(stdout, "%d\t%d\t%d\t%s\t%s\n", psPID, psUid, psGid, psState, psName);
-    }
-    closedir(dir);
-    exit(TRUE);
-}
+#if ENABLE_SELINUX
+       if (use_selinux)
+         printf("  PID Context                          Stat Command\n");
+       else
+#endif
+         printf("  PID  Uid     VmSize Stat Command\n");
+
+       while ((p = procps_scan(1)) != 0)  {
+               char *namecmd = p->cmd;
+#if ENABLE_SELINUX
+               if (use_selinux)
+                 {
+                       char sbuf[128];
+                       len = sizeof(sbuf);
+
+                       if (is_selinux_enabled()) {
+                         if (getpidcon(p->pid,&sid)<0)
+                           sid=NULL;
+                       }
+
+                       if (sid) {
+                         /*  I assume sid initilized with NULL  */
+                         len = strlen(sid)+1;
+                         safe_strncpy(sbuf, sid, len);
+                         freecon(sid);
+                         sid=NULL;
+                       }else {
+                         safe_strncpy(sbuf, "unknown",7);
+                       }
+                       len = printf("%5d %-32s %s ", p->pid, sbuf, p->state);
+               }
+               else
+#endif
+                 if(p->rss == 0)
+                   len = printf("%5d %-8s        %s ", p->pid, p->user, p->state);
+                 else
+                   len = printf("%5d %-8s %6ld %s ", p->pid, p->user, p->rss, p->state);
 
+               i = terminal_width-len;
+
+               if(namecmd && namecmd[0]) {
+                       if(i < 0)
+                               i = 0;
+                       if(strlen(namecmd) > (size_t)i)
+                               namecmd[i] = 0;
+                       printf("%s\n", namecmd);
+               } else {
+                       namecmd = p->short_cmd;
+                       if(i < 2)
+                               i = 2;
+                       if(strlen(namecmd) > ((size_t)i-2))
+                               namecmd[i-2] = 0;
+                       printf("[%s]\n", namecmd);
+               }
+               /* no check needed, but to make valgrind happy..  */
+               if (ENABLE_FEATURE_CLEAN_UP && p->cmd)
+                       free(p->cmd);
+       }
+       return EXIT_SUCCESS;
+}