about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--README39
-rw-r--r--px.149
-rw-r--r--px.c171
4 files changed, 205 insertions, 56 deletions
diff --git a/Makefile b/Makefile
index 59bd863..ae6e47e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 ALL=px
 
 CFLAGS=-g -O2 -Wall -Wno-switch -Wextra -Wwrite-strings
-LDFLAGS=-lprocps
+LDFLAGS=-lproc2
 
 DESTDIR=
 PREFIX=/usr/local
diff --git a/README b/README
new file mode 100644
index 0000000..da89814
--- /dev/null
+++ b/README
@@ -0,0 +1,39 @@
+PX(1)                       General Commands Manual                      PX(1)
+
+NAME
+     px – report details on matching processes
+
+SYNOPSIS
+     px [-f] PATTERNS ...
+
+DESCRIPTION
+     px searches the process list for processes matching any of the patterns
+     PATTERNS and prints details on them, namely PID, user, cpu usage, virtual
+     and real memory usage, start time, run time and cpu time, as well as the
+     full command line.
+
+     As PATTERNS may be used: substrings of the process name or numeric PIDs.
+
+     The options are as follows:
+
+     -f      Search the whole command line, including arguments.
+
+EXIT STATUS
+     The px utility returns 0 when a process was found, 1 if no process was
+     found, and 2 when other errors occured.
+
+SEE ALSO
+     ps(1), pgrep(2)
+
+AUTHORS
+     Leah Neukirchen <leah@vuxu.org>
+
+LICENSE
+     px is in the public domain.
+
+     To the extent possible under law, the creator of this work has waived all
+     copyright and related or neighboring rights to this work.
+
+     http://creativecommons.org/publicdomain/zero/1.0/
+
+Void Linux                        May 8, 2023                       Void Linux
diff --git a/px.1 b/px.1
new file mode 100644
index 0000000..d446cd0
--- /dev/null
+++ b/px.1
@@ -0,0 +1,49 @@
+.Dd May 08, 2023
+.Dt PX 1
+.Os
+.Sh NAME
+.Nm px
+.Nd report details on matching processes
+.Sh SYNOPSIS
+.Nm
+.Op Fl f
+.Ar PATTERNS ...
+.Sh DESCRIPTION
+.Nm
+searches the process list for processes matching any of the patterns
+.Ar PATTERNS
+and prints details on them,
+namely PID, user, cpu usage, virtual and real memory usage,
+start time, run time and cpu time, as well as the full command line.
+.Pp
+As
+.Ar PATTERNS
+may be used:
+substrings of the process name or numeric PIDs.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl f
+Search the whole command line, including arguments.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility returns 0 when a process was found,
+1 if no process was found,
+and 2 when other errors occured.
+.Sh SEE ALSO
+.Xr ps 1 ,
+.Xr pgrep 2
+.Sh AUTHORS
+.An Leah Neukirchen Aq Mt leah@vuxu.org
+.Sh LICENSE
+.Nm
+is in the public domain.
+.Pp
+To the extent possible under law,
+the creator of this work
+has waived all copyright and related or
+neighboring rights to this work.
+.Pp
+.Lk http://creativecommons.org/publicdomain/zero/1.0/
diff --git a/px.c b/px.c
index bf74d51..6172ecb 100644
--- a/px.c
+++ b/px.c
@@ -10,13 +10,18 @@
 #include <sys/sysinfo.h>
 
 #include <ctype.h>
+#include <errno.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <unistd.h>
 
-#include <proc/readproc.h>
+#include <libproc2/pids.h>
+#include <libproc2/stat.h>
+
+int fflag;
 
 static void
 print_human(intmax_t i)
@@ -56,70 +61,126 @@ print_time(time_t t) {
 int
 main(int argc, char *argv[])
 {
-	int clktck;
-	if ((clktck = getauxval(AT_CLKTCK)) <= 0)
-		if ((clktck = sysconf(_SC_CLK_TCK)) <= 0)
-			clktck = 100; 	/* educated guess */
-
-	struct sysinfo si;
-	sysinfo(&si);
-
+	int r;
+	pid_t me = getpid();
 	time_t now = time(0);
 
-	proc_t **result;
-	result = readproctab(PROC_FILLCOM | PROC_FILLUSR |
-	    PROC_FILLSTAT | PROC_FILLSTATUS);
+	struct stat_info *stat_info = 0;
+	if ((r = procps_stat_new(&stat_info)) < 0) {
+		fprintf(stderr, "failed to run procps_stat_new: %s\n",
+		    strerror(-r));
+		exit(2);
+	}
+	time_t boot_time = STAT_GET(stat_info, STAT_SYS_TIME_OF_BOOT, ul_int);
+	procps_stat_unref(&stat_info);
+
+	struct pids_info *Pids_info = 0;
+	enum pids_item items[] = {
+		PIDS_CMD,
+		PIDS_CMDLINE_V,
+		PIDS_ID_EUSER,
+		PIDS_ID_TID,
+		PIDS_STATE,
+		PIDS_TIME_ALL,
+		PIDS_TIME_ELAPSED,
+		PIDS_TIME_START,
+		PIDS_TTY_NAME,
+		PIDS_UTILIZATION,
+		PIDS_VM_RSS,
+		PIDS_VM_SIZE,
+	};
+	enum rel_items {
+		EU_CMD,
+		EU_CMDLINE_V,
+		EU_ID_EUSER,
+		EU_ID_TID,
+		EU_STATE,
+		EU_TIME_ALL,
+		EU_TIME_ELAPSED,
+		EU_TIME_START,
+		EU_TTY_NAME,
+		EU_UTILIZATION,
+		EU_VM_RSS,
+		EU_VM_SIZE,
+	};
+	if ((r = procps_pids_new(&Pids_info, items, 12)) < 0) {
+		fprintf(stderr, "failed to run procps_pids_new: %s\n",
+		    strerror(-r));
+		exit(2);
+	}
+
+	struct pids_fetch *reap = procps_pids_reap(Pids_info,
+	    PIDS_FETCH_TASKS_ONLY);
+	if (!reap) {
+		fprintf(stderr, "failed to run procps_pids_reap: %s\n",
+		    strerror(errno));
+		exit(2);
+	}
 
 	int matched = 0;
 
-	for (; *result; result++) {
-		proc_t *p = *result;
-
-		if (argc > 1) {
-			for (int i = 1; i < argc; i++) {
-				for (size_t j = 0; j < strlen(argv[i]); j++) {
-					if (!isdigit(argv[i][j]))
-						goto word;
-				}
-				if (p->tid == atoi(argv[i]))
-					goto match;
-				else
-					continue;
+	int c;
+        while ((c = getopt(argc, argv, "f")) != -1)
+                switch (c) {
+		case 'f': fflag = 1; break;
+                default:
+                        fprintf(stderr,
+			    "Usage: %s [-f] [PATTERN...]\n", argv[0]);
+                        exit(2);
+                }
+
+	int total_procs = reap->counts->total;
+	for (int i = 0; i < total_procs; i++) {
+#define PIDS_GETCHR(e) PIDS_VAL(EU_ ## e, s_ch, reap->stacks[i], Pids_info)
+#define PIDS_GETINT(e) PIDS_VAL(EU_ ## e, s_int, reap->stacks[i], Pids_info)
+#define PIDS_GETUNT(e) PIDS_VAL(EU_ ## e, u_int, reap->stacks[i], Pids_info)
+#define PIDS_GETULINT(e) PIDS_VAL(EU_ ## e, ul_int, reap->stacks[i], Pids_info)
+#define PIDS_GETREAL(e) PIDS_VAL(EU_ ## e, real, reap->stacks[i], Pids_info)
+#define PIDS_GETSTR(e) PIDS_VAL(EU_ ## e, str, reap->stacks[i], Pids_info)
+#define PIDS_GETSTR_V(e) PIDS_VAL(EU_ ## e, strv, reap->stacks[i], Pids_info)
+		if (argc <= optind)
+			goto match;
+
+		for (int j = optind; j < argc; j++) {
+			for (size_t k = 0; k < strlen(argv[j]); k++)
+				if (!isdigit(argv[j][k]))
+					goto word;
+			if (PIDS_GETINT(ID_TID) == atoi(argv[j]))
+				goto match;
+			else
+				continue;
 word:
-				if (strstr(p->cmd, argv[i]))
-					goto match;
+			if (fflag && PIDS_GETSTR_V(CMDLINE_V)) {
+				if (PIDS_GETINT(ID_TID) == me)
+					continue; /* we'd always match ourself */
+				for (int k = 0; PIDS_GETSTR_V(CMDLINE_V)[k]; k++)
+					if (strstr(PIDS_GETSTR_V(CMDLINE_V)[k], argv[j]))
+						goto match;
 			}
-			continue;
-match:
-			matched++;
-		} else {
-			matched++;
+			else if (strstr(PIDS_GETSTR(CMD), argv[j]))
+				goto match;
 		}
+		continue;
+
+match:
+		matched++;
 
 		if (matched == 1)
 			printf("  PID USER     %%CPU  VSZ  RSS START ELAPSED CPUTIME COMMAND\n");
 
-		printf("%5d", p->tid);
+		printf("%5d", PIDS_GETINT(ID_TID));
 
-		printf(" %-8.8s", p->euser);
+		printf(" %-8.8s", PIDS_GETSTR(ID_EUSER));
 
-		double pcpu = 0;
-		time_t seconds, cputime;
-		cputime = (p->utime + p->stime) / clktck;
-		seconds = si.uptime - p->start_time / clktck;
-		if (seconds)
-			pcpu = (cputime * 100.0) / seconds;
-		printf(" %4.1f", pcpu);
+		printf(" %4.1f", PIDS_GETREAL(UTILIZATION));
 
-		print_human(p->vm_size*1024);
+		print_human(PIDS_GETULINT(VM_SIZE)*1024);
 
-		print_human(p->vm_rss*1024);
+		print_human(PIDS_GETULINT(VM_RSS)*1024);
 
 		char buf[7];
-		time_t start;
-		time_t seconds_ago;
-		start = (now - si.uptime) + p->start_time / clktck;
-		seconds_ago = now - start;
+		time_t start = boot_time + PIDS_GETREAL(TIME_START);
+		time_t seconds_ago = now - start;
 		if (seconds_ago < 0)
 			seconds_ago = 0;
 		if (seconds_ago > 3600*24)
@@ -128,16 +189,16 @@ match:
 			strftime(buf, sizeof buf, "%H:%M", localtime(&start));
 		printf(" %s", buf);
 
-		print_time(seconds_ago);
+		print_time(PIDS_GETREAL(TIME_ELAPSED));
 
-		print_time(cputime);
+		print_time(PIDS_GETREAL(TIME_ALL));
 
-		if (p->cmdline)
-			for (int i = 0; p->cmdline[i]; i++)
-				printf(" %s", p->cmdline[i]);
-		else		// kernel threads
-			printf(" [%s]", p->cmd);
-		if (p->state == 'Z')
+		if (PIDS_GETSTR_V(CMDLINE_V))
+			for (int j = 0; PIDS_GETSTR_V(CMDLINE_V)[j]; j++)
+				printf(" %s", PIDS_GETSTR_V(CMDLINE_V)[j]);
+		else // kernel threads
+			printf(" [%s]", PIDS_GETSTR(CMD));
+		if (PIDS_GETCHR(STATE) == 'Z')
 			printf(" <defunct>");
 
 		printf("\n");