Netdev List
 help / color / mirror / Atom feed
* [PATCH iproute2] ss: add -P/--process-age option to display process runtime
@ 2026-09-15 18:35 Harshith Hari
  2026-09-15 20:44 ` Stephen Hemminger
  0 siblings, 1 reply; 2+ messages in thread
From: Harshith Hari @ 2026-09-15 18:35 UTC (permalink / raw)
  To: netdev; +Cc: stephen, Harshith Hari

Add a new option (-P/--process-age) to display process uptime/age
alongside process info inside socket user context output.

Signed-off-by: Harshith Hari <harshithhari000111@gmail.com>
---
 man/man8/ss.8 |   3 +
 misc/ss.c     | 456 ++++++++++++++++++++++++++++++--------------------
 2 files changed, 282 insertions(+), 177 deletions(-)

diff --git a/man/man8/ss.8 b/man/man8/ss.8
index b0629b82..5f345c21 100644
--- a/man/man8/ss.8
+++ b/man/man8/ss.8
@@ -163,6 +163,9 @@ the number of packets dropped before they are de-multiplexed into the socket
 .TP
 \.B \-P, \-\-process\-age
 Show process age/runtime alongside process socket information.
+.TP
+\.B \-P, \-\-process\-age
+Show process age/runtime alongside process socket information.
 Show processes using sockets.
 .TP
 .B \-T, \-\-threads
diff --git a/misc/ss.c b/misc/ss.c
index 6c32455d..66fb1fee 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -56,58 +56,58 @@ static int show_process_age;
 
 static void print_process_age(pid_t pid)
 {
-char path[64];
-FILE *f;
-unsigned long long starttime;
-double uptime = 0.0;
-long clock_ticks = sysconf(_SC_CLK_TCK);
-
-f = fopen("/proc/uptime", "r");
-if (!f)
-return;
-
-if (fscanf(f, "%lf", &uptime) != 1) {
-fclose(f);
-return;
-}
-fclose(f);
+	char path[64];
+	FILE *f;
+	unsigned long long starttime;
+	double uptime = 0.0;
+	long clock_ticks = sysconf(_SC_CLK_TCK);
+
+	f = fopen("/proc/uptime", "r");
+	if (!f)
+		return;
 
-snprintf(path, sizeof(path), "/proc/%d/stat", pid);
-f = fopen(path, "r");
-if (!f)
-return;
+	if (fscanf(f, "%lf", &uptime) != 1) {
+		fclose(f);
+		return;
+	}
+	fclose(f);
 
-char buf[1024];
+	snprintf(path, sizeof(path), "/proc/%d/stat", pid);
+	f = fopen(path, "r");
+	if (!f)
+		return;
 
-if (fgets(buf, sizeof(buf), f)) {
-char *ptr = strrchr(buf, ')');
+	char buf[1024];
 
-if (ptr) {
-int field = 3;
+	if (fgets(buf, sizeof(buf), f)) {
+		char *ptr = strrchr(buf, ')');
 
-ptr++;
-while (*ptr && field < 22) {
-if (*ptr == ' ')
-field++;
-ptr++;
-}
-if (sscanf(ptr, "%llu", &starttime) == 1) {
-double process_secs = uptime - ((double)starttime / clock_ticks);
-long secs = (long)process_secs;
-long hours = secs / 3600;
-long mins = (secs % 3600) / 60;
-long s = secs % 60;
+		if (ptr) {
+			int field = 3;
 
-if (hours > 0)
-out(",age=%ldh%ldm", hours, mins);
-else if (mins > 0)
-out(",age=%ldm%lds", mins, s);
-else
-out(",age=%lds", s);
-}
-}
-}
-fclose(f);
+			ptr++;
+			while (*ptr && field < 22) {
+				if (*ptr == ' ')
+					field++;
+				ptr++;
+			}
+			if (sscanf(ptr, "%llu", &starttime) == 1) {
+				double process_secs = uptime - ((double)starttime / clock_ticks);
+				long secs = (long)process_secs;
+				long hours = secs / 3600;
+				long mins = (secs % 3600) / 60;
+				long s = secs % 60;
+
+				if (hours > 0)
+					out(",age=%ldh%ldm", hours, mins);
+				else if (mins > 0)
+					out(",age=%ldm%lds", mins, s);
+				else
+					out(",age=%lds", s);
+			}
+		}
+	}
+	fclose(f);
 }
 
 
@@ -115,57 +115,58 @@ static int show_process_age;
 
 static void print_process_age(pid_t pid)
 {
-char path[64];
-FILE *f;
-unsigned long long starttime;
-double uptime = 0.0;
-long clock_ticks = sysconf(_SC_CLK_TCK);
+	char path[64];
+	FILE *f;
+	unsigned long long starttime;
+	double uptime = 0.0;
+	long clock_ticks = sysconf(_SC_CLK_TCK);
 
-f = fopen("/proc/uptime", "r");
-if (!f)
-return;
-if (fscanf(f, "%lf", &uptime) != 1) {
-fclose(f);
-return;
-}
-fclose(f);
+	f = fopen("/proc/uptime", "r");
+	if (!f)
+		return;
 
-snprintf(path, sizeof(path), "/proc/%d/stat", pid);
-f = fopen(path, "r");
-if (!f)
-return;
+	if (fscanf(f, "%lf", &uptime) != 1) {
+		fclose(f);
+		return;
+	}
+	fclose(f);
 
-char buf[1024];
+	snprintf(path, sizeof(path), "/proc/%d/stat", pid);
+	f = fopen(path, "r");
+	if (!f)
+		return;
 
-if (fgets(buf, sizeof(buf), f)) {
-char *ptr = strrchr(buf, ')');
+	char buf[1024];
 
-if (ptr) {
-int field = 3;
+	if (fgets(buf, sizeof(buf), f)) {
+		char *ptr = strrchr(buf, ')');
 
-ptr++;
-while (*ptr && field < 22) {
-if (*ptr == ' ')
-field++;
-ptr++;
-}
-if (sscanf(ptr, "%llu", &starttime) == 1) {
-double process_secs = uptime - ((double)starttime / clock_ticks);
-long secs = (long)process_secs;
-long hours = secs / 3600;
-long mins = (secs % 3600) / 60;
-long s = secs % 60;
+		if (ptr) {
+			int field = 3;
 
-if (hours > 0)
-out(",age=%ldh%ldm", hours, mins);
-else if (mins > 0)
-out(",age=%ldm%lds", mins, s);
-else
-out(",age=%lds", s);
-}
-}
-}
-fclose(f);
+			ptr++;
+			while (*ptr && field < 22) {
+				if (*ptr == ' ')
+					field++;
+				ptr++;
+			}
+			if (sscanf(ptr, "%llu", &starttime) == 1) {
+				double process_secs = uptime - ((double)starttime / clock_ticks);
+				long secs = (long)process_secs;
+				long hours = secs / 3600;
+				long mins = (secs % 3600) / 60;
+				long s = secs % 60;
+
+				if (hours > 0)
+					out(",age=%ldh%ldm", hours, mins);
+				else if (mins > 0)
+					out(",age=%ldm%lds", mins, s);
+				else
+					out(",age=%lds", s);
+			}
+		}
+	}
+	fclose(f);
 }
 
 
@@ -892,12 +893,12 @@ static int find_entry(unsigned int ino, char **buf, int type)
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
@@ -1088,12 +1089,12 @@ static const char *unix_netid_name(int type)
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
@@ -1114,12 +1115,12 @@ static const char *proto_name(int protocol)
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
@@ -1147,12 +1148,12 @@ static const char *vsock_netid_name(int type)
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
@@ -1172,12 +1173,12 @@ static const char *tipc_netid_name(int type)
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
@@ -1656,12 +1657,12 @@ static void sock_state_print(struct sockstat *s)
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
@@ -2037,12 +2038,12 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s)
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
@@ -2174,12 +2175,12 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode)
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
@@ -2727,42 +2728,76 @@ static void proc_ctx_print(struct sockstat *s)
 		if (find_entry(s->ino, &buf,
 				(show_proc_ctx & show_sock_ctx) ?
 				PROC_SOCK_CTX : PROC_CTX) > 0) {
-			out(" users:(%s)", buf);
+			if (show_process_age) {
+				char *ptr_p = buf;
+
+				out(" users:(");
+				while (*ptr_p) {
+					char *pid_ptr = strstr(ptr_p, "pid=");
+
+					if (pid_ptr) {
+						char *close_paren = strchr(pid_ptr, ')');
+
+						if (close_paren) {
+							out("%.*s",
+				    (int)(close_paren - ptr_p),
+				    ptr_p);
+							pid_t pid = atoi(pid_ptr + 4);
+
+							if (pid > 0)
+								print_process_age(pid);
+							out(")");
+							ptr_p = close_paren + 1;
+						} else {
+							out("%s", ptr_p);
+							break;
+						}
+					} else {
+						out("%s", ptr_p);
+						break;
+					}
+				}
+				out(")");
+			} else {
+				out(" users:(%s)", buf);
+			}
 			free(buf);
 		}
 	} else if (show_processes || show_threads) {
 if (find_entry(s->ino, &buf, USERS) > 0) {
 if (show_process_age) {
-char *p = buf;
-
-out(" users:(");
-while (*p) {
-char *pid_ptr = strstr(p, "pid=");
-
-if (pid_ptr) {
-char *close_paren = strchr(pid_ptr, ')');
-
-if (close_paren) {
-out("%.*s", (int)(close_paren - p), p);
-pid_t pid = atoi(pid_ptr + 4);
-
-if (pid > 0)
-print_process_age(pid);
-out(")");
-p = close_paren + 1;
-} else {
-out("%s", p);
-break;
-}
-} else {
-out("%s", p);
-break;
-}
-}
-out(")");
-} else {
-out(" users:(%s)", buf);
-}
+				char *ptr_p = buf;
+
+				out(" users:(");
+				while (*ptr_p) {
+					char *pid_ptr = strstr(ptr_p, "pid=");
+
+					if (pid_ptr) {
+						char *close_paren = strchr(pid_ptr, ')');
+
+						if (close_paren) {
+							out("%.*s",
+				    (int)(close_paren - ptr_p),
+				    ptr_p);
+							pid_t pid = atoi(pid_ptr + 4);
+
+							if (pid > 0)
+								print_process_age(pid);
+							out(")");
+							ptr_p = close_paren + 1;
+						} else {
+							out("%s", ptr_p);
+							break;
+						}
+					} else {
+						out("%s", ptr_p);
+						break;
+					}
+				}
+				out(")");
+			} else {
+				out(" users:(%s)", buf);
+			}
 free(buf);
 }
 } else {
@@ -3245,12 +3280,12 @@ static void tcp_tls_version(struct rtattr *attr)
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
@@ -3279,12 +3314,12 @@ static void tcp_tls_cipher(struct rtattr *attr)
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
@@ -3310,12 +3345,12 @@ static void tcp_tls_conf(const char *name, struct rtattr *attr)
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
@@ -3673,12 +3708,12 @@ static const char *format_host_sa(struct sockaddr_storage *sa)
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
@@ -5831,12 +5866,12 @@ static int generic_show_sock(struct nlmsghdr *nlh, void *arg)
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
@@ -6217,10 +6252,69 @@ wrong_state:
 #define OPT_BPF_MAPS 263
 #define OPT_BPF_MAP_ID 264
 
+static int show_process_age;
+
+static void print_process_age(pid_t pid)
+{
+	char path[64];
+	FILE *f;
+	unsigned long long starttime;
+	double uptime = 0.0;
+	long clock_ticks = sysconf(_SC_CLK_TCK);
+
+	f = fopen("/proc/uptime", "r");
+	if (!f)
+		return;
+
+	if (fscanf(f, "%lf", &uptime) != 1) {
+		fclose(f);
+		return;
+	}
+	fclose(f);
+
+	snprintf(path, sizeof(path), "/proc/%d/stat", pid);
+	f = fopen(path, "r");
+	if (!f)
+		return;
+
+	char buf[1024];
+
+	if (fgets(buf, sizeof(buf), f)) {
+		char *ptr = strrchr(buf, ')');
+
+		if (ptr) {
+			int field = 3;
+
+			ptr++;
+			while (*ptr && field < 22) {
+				if (*ptr == ' ')
+					field++;
+				ptr++;
+			}
+			if (sscanf(ptr, "%llu", &starttime) == 1) {
+				double process_secs = uptime - ((double)starttime / clock_ticks);
+				long secs = (long)process_secs;
+				long hours = secs / 3600;
+				long mins = (secs % 3600) / 60;
+				long s = secs % 60;
+
+				if (hours > 0)
+					out(",age=%ldh%ldm", hours, mins);
+				else if (mins > 0)
+					out(",age=%ldm%lds", mins, s);
+				else
+					out(",age=%lds", s);
+			}
+		}
+	}
+	fclose(f);
+}
+
 static const struct option long_opts[] = {
 	{ "process-age", no_argument, NULL, 'P' },
 	{ "process-age", no_argument, NULL, 'P' },
 	{ "process-age", no_argument, NULL, 'P' },
+	{ "process-age", no_argument, NULL, 'P' },
 	{ "numeric", 0, 0, 'n' },
 	{ "resolve", 0, 0, 'r' },
 	{ "options", 0, 0, 'o' },
@@ -6283,20 +6377,28 @@ int main(int argc, char *argv[])
 	int ch;
 	int state_filter = 0;
 
+		case 'P':
+			show_process_age = 1;
+		show_processes = 1;
+		break;
 	while ((ch = getopt_long(argc, argv,
 				 "halBetuwxnro460spTbEf:mMiA:D:F:vVzZN:KHQSOPPP",
 				 long_opts, NULL)) != EOF) {
 		switch (ch) {
+		case 'P':
+			show_process_age = 1;
+		show_processes = 1;
+		break;
 	case \'P\':
 		show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
-	case 'P':
-		show_process_age = 1;
+		case 'P':
+			show_process_age = 1;
 		show_processes = 1;
 		break;
 	
-- 
2.43.7


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH iproute2] ss: add -P/--process-age option to display process runtime
  2026-09-15 18:35 [PATCH iproute2] ss: add -P/--process-age option to display process runtime Harshith Hari
@ 2026-09-15 20:44 ` Stephen Hemminger
  0 siblings, 0 replies; 2+ messages in thread
From: Stephen Hemminger @ 2026-09-15 20:44 UTC (permalink / raw)
  To: Harshith Hari; +Cc: netdev

On Wed, 16 Sep 2026 00:05:22 +0530
Harshith Hari <harshithhari000111@gmail.com> wrote:

> Add a new option (-P/--process-age) to display process uptime/age
> alongside process info inside socket user context output.
> 
> Signed-off-by: Harshith Hari <harshithhari000111@gmail.com>
> ---

Your mailing method is mangling whitespace and the patch will not apply cleanly
to the current iproute2 tree. Suggest fixing your settings and use git send-email.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-15 20:44 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-15 18:35 [PATCH iproute2] ss: add -P/--process-age option to display process runtime Harshith Hari
2026-09-15 20:44 ` Stephen Hemminger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox