From 0ccc9f3c530417019a2301585cec1ae307125a19 Mon Sep 17 00:00:00 2001
From: kzak <kzak@fedoraproject.org>
Date: Wed, 9 Aug 2006 21:46:34 +0000
Subject: [PATCH] fix problem with threads

---
 lsof.spec                |   9 ++-
 lsof_4.78C-threads.patch | 124 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 132 insertions(+), 1 deletion(-)
 create mode 100644 lsof_4.78C-threads.patch

diff --git a/lsof.spec b/lsof.spec
index bfcddc4..7ff0203 100644
--- a/lsof.spec
+++ b/lsof.spec
@@ -1,7 +1,7 @@
 Summary: A utility which lists open files on a Linux/UNIX system.
 Name: lsof
 Version: 4.78
-Release: 1
+Release: 2
 License: Free
 %define lsofrh lsof_4.78C-rh
 Group: Development/Debuggers
@@ -12,6 +12,8 @@ BuildRoot: %{_tmppath}/%{name}-root
 
 BuildRequires: libselinux-devel
 
+Patch1: lsof_4.78C-threads.patch
+
 %description
 Lsof stands for LiSt Open Files, and it does just that: it lists
 information about files that are open by the processes running on a
@@ -20,6 +22,8 @@ UNIX system.
 %prep
 %setup -q -n %{lsofrh}
 
+%patch1 -p1 -b .kzak
+
 %build
 LSOF_VSTR=2.6.16 LINUX_BASE=/proc ./Configure -n linux
 
@@ -42,6 +46,9 @@ rm -rf ${RPM_BUILD_ROOT}
 %{_mandir}/man*/*
 
 %changelog
+* Wed Aug  9 2006 Karel Zak <kzak@redhat.com> 4.78-2
+- fix #184338 - allow lsof access nptl threads
+
 * Wed Jul 19 2006 Karel Zak <kzak@redhat.com> 4.78-1
 - rebuild
 
diff --git a/lsof_4.78C-threads.patch b/lsof_4.78C-threads.patch
new file mode 100644
index 0000000..58284e2
--- /dev/null
+++ b/lsof_4.78C-threads.patch
@@ -0,0 +1,124 @@
+--- lsof_4.78C-rh/dialects/linux/dproc.c.kzak	2006-06-12 19:10:05.000000000 +0200
++++ lsof_4.78C-rh/dialects/linux/dproc.c	2006-08-09 23:25:14.000000000 +0200
+@@ -69,7 +69,8 @@
+ _PROTOTYPE(static int read_proc_stat,(char *p, int pid, char **cmd, int *ppid,
+ 	   int *pgid));
+ _PROTOTYPE(static int statEx,(char *p, struct stat *s, int *ss));
+- 
++_PROTOTYPE(static int get_other_thread,(int pid, char **tid));
++
+ 
+ #if	defined(HASSELINUX)
+ _PROTOTYPE(static int cmp_cntx_eq,(char *pcntx, char *ucntx));
+@@ -148,6 +149,7 @@
+ 	static char *path = (char *)NULL;
+ 	static int pathl = 0;
+ 	int pgid, pid, ppid;
++	char *tid = NULL;
+ 	static char *pidpath = (char *)NULL;
+ 	static MALLOC_S pidpathl = 0;
+ 	static MALLOC_S pidx = 0;
+@@ -253,6 +255,13 @@
+ 	    }
+ 	    if (f)
+ 		continue;
++
++	    tid = NULL;
++	    if (get_other_thread(pid, &tid) < 0)
++		continue;
++	    if (tid)
++		n += sizeof("task/") + strlen(tid);
++
+ 	/*
+ 	 * Build path to PID's directory.
+ 	 */
+@@ -266,7 +275,14 @@
+ 		    Exit(1);
+ 		}
+ 	    }
+-	    (void) snpf(pidpath + pidx, pidpathl - pidx, "%s/", dp->d_name);
++	    if (tid) {
++		/* /proc/<pid> is useless (zombie), we have to use /proc/<pid>/task/<tid>
++		 * where is still running thread
++		 */
++		(void) snpf(pidpath + pidx, pidpathl - pidx, "%s/task/%s/", dp->d_name, tid);
++		free(tid);
++	    } else
++		(void) snpf(pidpath + pidx, pidpathl - pidx, "%s/", dp->d_name);
+ 	    n += (pidx + 1);
+ 	/*
+ 	 * Process the PID's stat info.
+@@ -897,6 +913,60 @@
+ 	(void) fclose(ms);
+ }
+ 
++/* fill tid if the initial thread is zombie, 
++ * but other thread still alive 
++ *
++ * returns -1=error, 0=nothing, 1=ok
++ */
++static int
++get_other_thread(pid, tid)
++	int pid;
++	char **tid;
++{
++	char path[MAXPATHLEN];
++	DIR *tdp;
++	struct dirent *td;
++	char pstate;
++	FILE *f;
++	int _pid;
++	int re = 0;
++
++	snpf(path, sizeof(path), "%s/%d/stat", PROCFS, pid);
++	if (!(f = fopen(path, "r")))
++		return;
++	fscanf(f, "%d %*s %c", &_pid, &pstate);
++	fclose(f);
++	if (_pid != pid)
++		return -1;		/* corrupted /proc? */
++	if (pstate!='Z') 
++		return 0;		/* ignore normal proceses */
++
++	snpf(path, sizeof(path), "%s/%d/task", PROCFS, pid);
++
++	/* open /proc/<pid>/task */
++	if (!(tdp = opendir(path)))
++		return 0;		/* kernel < 2.6.x */
++	
++	/* look for first alive thread */
++	while ((td = readdir(tdp))) {
++		if (strcmp(td->d_name, ".")==0 || strcmp(td->d_name, "..")==0)
++			continue;
++		
++		/* /proc/<pid>/task/<tid>/stat */
++		snpf(path, sizeof(path), "%s/%d/task/%s/stat", PROCFS, pid, td->d_name);
++		if (!(f = fopen(path, "r")))
++			continue;
++		fscanf(f, "%*d %*s %c", &pstate);
++		fclose(f);
++		if (pstate!='Z') {
++			re = 1;
++			*tid = strdup(td->d_name);
++			break;
++		}
++	}
++	closedir(tdp);
++	return re;
++}
+ 
+ /*
+  * read_proc_stat() - read process status
+@@ -931,12 +1001,6 @@
+ 	if ((nf = get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0)) < 5)
+ 	    return(1);
+ /*
+- * Convert the first field to an integer; its conversion must match the
+- * PID argument.
+- */
+-	if (atoi(fp[0]) != pid)
+-	    return(1);
+-/*
+  * Get the command name from the second field.  Strip a starting '(' and
+  * an ending ')'.  Allocate space to hold the result and return the space
+  * pointer.