svn commit: trunk/busybox: include procps

vda at busybox.net vda at busybox.net
Sun Nov 5 00:45:47 UTC 2006


Author: vda
Date: 2006-11-04 16:45:47 -0800 (Sat, 04 Nov 2006)
New Revision: 16511

Log:
ps: implement POSIX-like options, most notably -o
(activated by CONFIG_DESKTOP)


Modified:
   trunk/busybox/include/usage.h
   trunk/busybox/procps/ps.c


Changeset:
Modified: trunk/busybox/include/usage.h
===================================================================
--- trunk/busybox/include/usage.h	2006-11-05 00:44:39 UTC (rev 16510)
+++ trunk/busybox/include/usage.h	2006-11-05 00:45:47 UTC (rev 16511)
@@ -2377,6 +2377,18 @@
 	"$ printf \"Val=%d\\n\" 5\n" \
 	"Val=5\n"
 
+
+#if ENABLE_DESKTOP
+
+#define ps_trivial_usage \
+	""
+#define ps_full_usage \
+	"Report process status\n" \
+	"\nOptions:" \
+	"\n\t-o col1,col2=header\tSelect columns for display" \
+
+#else /* !ENABLE_DESKTOP */
+
 #if !defined CONFIG_SELINUX && !ENABLE_FEATURE_PS_WIDE
 #define USAGE_PS "\n\tThis version of ps accepts no options."
 #else
@@ -2396,6 +2408,8 @@
 	USE_SELINUX("\n\t-c\tshow SE Linux context") \
 	USAGE_PS_WIDE("\n\tw\twide output")
 
+#endif /* ENABLE_DESKTOP */
+
 #define ps_example_usage \
 	"$ ps\n" \
 	"  PID  Uid      Gid State Command\n" \
@@ -2409,6 +2423,7 @@
 	"  745 root     root     S [getty]\n" \
 	" 2990 andersen andersen R ps\n"
 
+
 #define pwd_trivial_usage \
 	""
 #define pwd_full_usage \

Modified: trunk/busybox/procps/ps.c
===================================================================
--- trunk/busybox/procps/ps.c	2006-11-05 00:44:39 UTC (rev 16510)
+++ trunk/busybox/procps/ps.c	2006-11-05 00:45:47 UTC (rev 16511)
@@ -9,8 +9,281 @@
 
 #include "busybox.h"
 
+#if ENABLE_DESKTOP
+
+/* Print value to buf, max size+1 chars (including trailing '\0') */
+
+void func_user(char *buf, int size, const procps_status_t *ps)
+{
+	safe_strncpy(buf, get_cached_username(ps->uid), size+1);
+}
+
+void func_comm(char *buf, int size, const procps_status_t *ps)
+{
+	safe_strncpy(buf, ps->comm, size+1);
+}
+
+void func_args(char *buf, int size, const procps_status_t *ps)
+{
+	buf[0] = '\0';
+	if (ps->cmd)
+		safe_strncpy(buf, ps->cmd, size+1);
+	else if (size >= 2)
+		snprintf(buf, size+1, "[%.*s]", size-2, ps->comm);
+}
+
+void func_pid(char *buf, int size, const procps_status_t *ps)
+{
+	snprintf(buf, size+1, "%*u", size, ps->pid);
+}
+
+void func_ppid(char *buf, int size, const procps_status_t *ps)
+{
+	snprintf(buf, size+1, "%*u", size, ps->ppid);
+}
+
+void func_pgid(char *buf, int size, const procps_status_t *ps)
+{
+	snprintf(buf, size+1, "%*u", size, ps->pgid);
+}
+
+void func_rss(char *buf, int size, const procps_status_t *ps)
+{
+	char buf5[5];
+	smart_ulltoa5( ((unsigned long long)ps->rss) << 10, buf5);
+	snprintf(buf, size+1, "%.*s", size, buf5);
+}
+
+/*
+void func_nice(char *buf, int size, const procps_status_t *ps)
+{
+	ps->???
+}
+
+void func_etime(char *buf, int size, const procps_status_t *ps)
+{
+	elapled time [[dd-]hh:]mm:ss
+}
+
+void func_time(char *buf, int size, const procps_status_t *ps)
+{
+	cumulative time [[dd-]hh:]mm:ss
+}
+
+void func_pcpu(char *buf, int size, const procps_status_t *ps)
+{
+}
+
+void func_tty(char *buf, int size, const procps_status_t *ps)
+{
+}
+*/
+
+typedef struct {
+	char name[8];
+	const char *header;
+	void (*f)(char *buf, int size, const procps_status_t *ps);
+	int ps_flags;
+	int width;
+} ps_out_t;
+
+static const ps_out_t out_spec[] = {
+// Mandated by POSIX:
+	{ "user"  ,"USER"   ,func_user  ,PSSCAN_UIDGID,8                   },
+	{ "comm"  ,"COMMAND",func_comm  ,PSSCAN_COMM  ,16                  },
+	{ "args"  ,"COMMAND",func_args  ,PSSCAN_CMD|PSSCAN_COMM,256        },
+	{ "pid"   ,"PID"    ,func_pid   ,PSSCAN_PID   ,5                   },
+	{ "ppid"  ,"PPID"   ,func_ppid  ,PSSCAN_PPID  ,5                   },
+	{ "pgid"  ,"PGID"   ,func_pgid  ,PSSCAN_PGID  ,5                   },
+//	{ "etime" ,"ELAPSED",func_etime ,PSSCAN_      ,sizeof("ELAPSED")-1 },
+//	{ "group" ,"GROUP"  ,func_group ,PSSCAN_UIDGID,sizeof("GROUP"  )-1 },
+//	{ "nice"  ,"NI"     ,func_nice  ,PSSCAN_      ,sizeof("NI"     )-1 },
+//	{ "pcpu"  ,"%CPU"   ,func_pcpu  ,PSSCAN_      ,sizeof("%CPU"   )-1 },
+//	{ "rgroup","RGROUP" ,func_rgroup,PSSCAN_UIDGID,sizeof("RGROUP" )-1 },
+//	{ "ruser" ,"RUSER"  ,func_ruser ,PSSCAN_UIDGID,sizeof("RUSER"  )-1 },
+//	{ "time"  ,"TIME"   ,func_time  ,PSSCAN_      ,sizeof("TIME"   )-1 },
+//	{ "tty"   ,"TT"     ,func_tty   ,PSSCAN_      ,sizeof("TT"     )-1 },
+//	{ "vsz"   ,"VSZ"    ,func_vsz   ,PSSCAN_VSZ   ,4                   },
+// Not mandated by POSIX:
+	{ "rss"   ,"RSS"    ,func_rss   ,PSSCAN_RSS   ,4                   },
+};
+
+#define VEC_SIZE(v) ( sizeof(v) / sizeof((v)[0]) )
+
+static ps_out_t* out;
+static int out_cnt;
+static int print_header;
+static int ps_flags;
+static char *buffer;
+static unsigned terminal_width;
+
+
+static ps_out_t* new_out_t(void)
+{
+	int i = out_cnt++;
+	out = xrealloc(out, out_cnt * sizeof(*out));
+	return &out[i];
+}
+
+static const ps_out_t* find_out_spec(const char *name)
+{
+	int i;
+	for (i = 0; i < VEC_SIZE(out_spec); i++) {
+		if (!strcmp(name, out_spec[i].name))
+			return &out_spec[i];
+	}
+	bb_error_msg_and_die("bad -o argument '%s'", name);
+}
+
+static void parse_o(char* opt)
+{
+	ps_out_t* new;
+	// POSIX: "-o is blank- or comma-separated list" (FIXME)
+	char *comma, *equal;
+	while (1) {
+		comma = strchr(opt, ',');
+		equal = strchr(opt, '=');
+		if (comma && (!equal || equal > comma)) {
+			*comma = '\0';
+			*new_out_t() = *find_out_spec(opt);
+			*comma = ',';
+			opt = comma + 1;
+			continue;
+		}
+		break;
+	}
+	new = new_out_t();
+	if (equal)
+		*equal = '\0';
+	*new = *find_out_spec(opt);
+	if (equal) {
+		*equal = '=';
+		new->header = equal + 1;
+		// POSIX: the field widths shall be ... at least as wide as
+		// the header text (default or overridden value).
+		// If the header text is null, such as -o user=,
+		// the field width shall be at least as wide as the
+		// default header text
+		if (new->header[0]) {
+			new->width = strlen(new->header);
+			print_header = 1;
+		}
+	} else
+		print_header = 1;
+}
+
+static void post_process(void)
+{
+	int i;
+	int width = 0;
+	for (i = 0; i < out_cnt; i++) {
+		ps_flags |= out[i].ps_flags;
+		if (out[i].header[0]) {
+			print_header = 1;
+		}
+		width += out[i].width + 1; /* "FIELD " */
+	}
+	buffer = xmalloc(width + 1); /* for trailing \0 */
+}
+
+static void format_header(void)
+{
+	int i;
+	ps_out_t* op;
+	char *p = buffer;
+	if (!print_header)
+		return;
+	i = 0;
+	if (out_cnt) {
+		while (1) {
+			op = &out[i];
+			if (++i == out_cnt) /* do not pad last field */
+				break;
+			p += sprintf(p, "%-*s ", op->width, op->header);
+		}
+		strcpy(p, op->header);
+	}
+	printf("%.*s\n", terminal_width, buffer);
+}
+
+static void format_process(const procps_status_t *ps)
+{
+	int i, len;
+	char *p = buffer;
+	i = 0;
+	if (out_cnt) while (1) {
+		out[i].f(p, out[i].width, ps);
+		// POSIX: Any field need not be meaningful in all
+		// implementations. In such a case a hyphen ( '-' )
+		// should be output in place of the field value.
+		if (!*p) {
+			*p++ = '-';
+			*p = '\0';
+		}
+		len = strlen(p);
+		p += len;
+		len = out[i].width - len + 1;
+		if (++i == out_cnt) /* do not pad last field */
+			break;
+		while (len--)
+			*p++ = ' ';
+		*p = '\0';
+	}
+	printf("%.*s\n", terminal_width, buffer);
+}
+
+/* Cannot be const: parse_o() will choke */
+static char default_o[] = "pid,user" /* TODO: ,vsz,stat */ ",args";
+
 int ps_main(int argc, char **argv)
 {
+	procps_status_t *p;
+	llist_t* opt_o = NULL;
+
+	// POSIX:
+	// -a  Write information for all processes associated with terminals
+	//     Implementations may omit session leaders from this list
+	// -A  Write information for all processes
+	// -d  Write information for all processes, except session leaders
+	// -e  Write information for all processes (equivalent to -A.)
+	// -f  Generate a full listing
+	// -l  Generate a long listing
+	// -o col1,col2,col3=header
+	//     Select which columns to distplay
+	/* We allow (and ignore) most of the above. FIXME */
+	opt_complementary = "o::";
+	getopt32(argc, argv, "o:aAdefl", &opt_o);
+	if (opt_o) {
+		opt_o = rev_llist(opt_o);
+		do {
+			parse_o(opt_o->data);
+			opt_o = opt_o->link;
+		} while (opt_o);
+	} else
+		parse_o(default_o);
+	post_process();
+
+	terminal_width = INT_MAX;
+	if (isatty(1)) {
+		get_terminal_width_height(1, &terminal_width, NULL);
+		terminal_width--;
+	}
+	format_header();
+
+	p = NULL;
+	while ((p = procps_scan(p, ps_flags))) {
+		format_process(p);
+	}
+
+	return EXIT_SUCCESS;
+}
+
+
+#else /* !ENABLE_DESKTOP */
+
+
+int ps_main(int argc, char **argv)
+{
 	procps_status_t *p = NULL;
 	int i, len;
 	SKIP_SELINUX(const) int use_selinux = 0;
@@ -111,3 +384,5 @@
 		clear_username_cache();
 	return EXIT_SUCCESS;
 }
+
+#endif




More information about the busybox-cvs mailing list