/*
 * General Public License (GPL) v2
 *
 * 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 2007 jjmora@arrakis.es.  All rights reserved.
 * Use is subject to license terms.
*/

/* 
 * Version 0.1.1
*/

/*
 * Este programa acepta como parametro el PID de un proceso
 * y utiliza las fucniones de la libreria libkvm para obtener
 * el estado de los descriptores de fichero de un proceso.
 *
 * Uso: lwpfd [-f|-s|-r|-i|-a|-q|-x] [-T seconds] [-t LWPID,LWPID,LWPID,...] -p <pid>
 *
 *           -f show file descriptors.
 *           -i sort by LWPID.
 *           -s sort by systemcall.
 *           -r reverse sort.
 *           -a show all LWP.
 *           -t LWPID LWPID ... show this LWP list.
 *           -q output quick.
 *           -x Statistics.
 *           -p <pid> process ID.
 *
 *
 * IMPORTANTE: Este programa debe compilarse con la opcion de soporte para
 *             64bits, en gcc es "-m64". Tambien se debe utilizar "-lkvm" 
 *             para linkar la libreria libkvm
*/

/*
 * This program accept a process's ID and use the function
 * of the libkvm library to obtain the state of all threads.
 *
 * Usage: lwpfd [-f|-s|-r|-i|-a|-q|-x] [-T seconds] [-t LWPID,LWPID,LWPID,...] -p <pid>
 *
 *           -f show file descriptors.
 *           -i sort by LWPID.
 *           -s sort by systemcall.
 *           -r reverse sort.
 *           -a show all LWP.
 *           -t LWPID LWPID ... show this LWP list.
 *           -q output quick.
 *           -x Statistics.
 *           -p <pid> process ID.
 *
 *
 *
 * IMPORTANT: This program must be compiled with the option to 64bits support,
 *            in gcc compiler is "-m64". Also we must be compiled with "-lkvm"
 *            to support the libkvm library.
 *
*/


#include <stdio.h>
#include <limits.h>
#include <sys/times.h>


#include <sys/socket.h>
#include <sys/socketvar.h>
#include <strings.h>


#include <netinet/in.h>
#include <sys/fs/ufs_inode.h>

#include <fcntl.h>
#include <unistd.h>
#include <sys/klwp.h>
#include <sys/sobject.h> 
#include <sys/turnstile.h>
#include <sys/termios.h>
#include <sys/file.h>
#include <sys/fs/tmpnode.h>
#include <sys/fs/fifonode.h>
#include <sys/fs/snode.h>
#include <sys/vfs.h>
#include <sys/fstyp.h>
#include <sys/fsid.h>


#define _KMEMUSER
#include <kvm.h>

#define _KERNEL
#include <sys/fs/namenode.h>

#include "sysc.h"


#define TXT_SZ_FD 200

struct thread_info {
        int t_tid;
        clock_t   t_disp_time;
        int t_state;
        unsigned char t_sysnum;
        long lwp_arg[2];
        int     a_fd[50];
        int     a_nfd;
};


struct fd_info {
        int fd;
        char text[TXT_SZ_FD];
};


void ErrorParam();
int NumLines();
char *inet2char(int addrf, const void *addr, char *str);
int read_fd_list(kvm_t *kvm_p,proc_t *pproc,struct fd_info **fd_list);

void read_thread_info(kvm_t *kvm_p,proc_t *pproc,int nthreads,struct thread_info *p_thread_info,int *nlwp_time);




int main(int argc, char **argv,char **envp)
{
int n,j,k;
int nthreads;
char cad[80];
char str[50];

kvm_t *kvm_p;

struct pid pid;
proc_t *pproc;
int npid;
int pid_ok;

int sort_ok;
int SORT;
int REVERSE;

struct tms tms;
ulong clock_actual;
long seg,min,minx,hor;
int nlwp_time[6];

ulong val,val1;
int list_lwp[20];
int n_lwp;
int c;
int i;
int view_ok;
int argv_all;
int argv_quick;

int nsec;
int sec_ok;

int VIEW;
int cont_l;

struct fd_info *fd_list;
int nfd_info;

struct thread_info *p_thread_info;
struct thread_info aux_thread_info;

int syscall_stat[256];

init_sysc(&syscalltable);


view_ok=0;
SORT=0;
npid=0;
pid_ok=0;
nsec=1;
sec_ok=0;
REVERSE=0;
VIEW=0;
argv_all=0;
argv_quick=0;
n_lwp=0;

for(n=1;n<argc;n++)
	{

        if (!strcmp(argv[n],"-f"))
		VIEW=1; 
        if (!strcmp(argv[n],"-s"))
		SORT=2; 
        if (!strcmp(argv[n],"-i"))
                SORT=3; 
        if (!strcmp(argv[n],"-a"))
                argv_all=1;
        if (!strcmp(argv[n],"-r"))
                REVERSE=1; 
        if (!strcmp(argv[n],"-q"))
                argv_quick=1; 
        if (!strcmp(argv[n],"-x"))
                VIEW=3; 
	if (!strcmp(argv[n],"-p"))
                { 
		if(n+1<argc)
			npid=atoi(argv[n+1]);pid_ok=1; 
		}

        if (!strcmp(argv[n],"-T"))
                {
                if(n+1<argc)
                        nsec=atoi(argv[n+1]);sec_ok=1;
                }


        if (!strcmp(argv[n],"-t"))
                {
                c=0;
                n++;
                i=n;
                while (i<argc)
                        {
                        if (atoi(argv[i]))
                                {
                                list_lwp[c]=atoi(argv[i]);
                                c++;
                                }
                                else
                                {i=argc;}
                        i++;
                        }
                n_lwp=c;
                n=n+c;
                }

	}

if(!pid_ok)
	{ErrorParam("Falta el <pid>");return(1);}

for(;;)
	{
	kvm_p=kvm_open(NULL,NULL,NULL,O_RDONLY,cad);
	if(kvm_p==NULL)
		{printf("\n kvm_open ERROR %s\n\n",cad);return(1);}

	/*
 	* Se obtiene un puntero a una estructura de tipo proc_t
	*/

	pproc=kvm_getproc(kvm_p,npid);

	if(pproc==NULL)
		{
		printf("El proceso no existe\n");
		return(1);
		}

	if(kvm_read(kvm_p,(uintptr_t)pproc->p_pidp,&pid,sizeof(pid))<0)
        	{printf("\nkvm_read: Error leyendo p_pidp");}

	nthreads=pproc->p_lwpcnt;

	printf("\n Pid: %d  \tPPid: %d   Threads: %d",pid.pid_id,pproc->p_ppid,nthreads);
	printf("\n Args: %s",pproc->p_user.u_psargs); 
	printf("\n");

	p_thread_info=malloc(sizeof(struct thread_info)*nthreads);
	if(p_thread_info==NULL)
		{printf("\n malloc(): Error no se ha podido reservar memoria \n\n",cad);return(1);}	


	fd_list=NULL;
	nfd_info=read_fd_list(kvm_p,pproc,&fd_list);
	
	read_thread_info(kvm_p,pproc,nthreads,p_thread_info,nlwp_time);

	kvm_close(kvm_p);

/* 
 * Ordena el array p_thread_info[] 
*/

	val=0;
	val1=0;
	sort_ok=1;
	for(n=0;n<256;n++)
		 {syscall_stat[n]=0;}

	while(sort_ok)
		{
		sort_ok=0;
		for (n=0;n<nthreads-1;n++)
			{
			if (SORT==2)
				{val=(ulong)p_thread_info[n].t_sysnum;val1=(ulong)p_thread_info[n+1].t_sysnum;}

			if (SORT==0)
				{val=(ulong)p_thread_info[n+1].t_disp_time;val1=(ulong)p_thread_info[n].t_disp_time;}


			if(REVERSE)
				{
				if(val<val1)
					{
					aux_thread_info=p_thread_info[n];
					p_thread_info[n]=p_thread_info[n+1];
					p_thread_info[n+1]=aux_thread_info;
					sort_ok=1;
					}	
				}
				else
				{
				if(val>val1)
					{
                                	aux_thread_info=p_thread_info[n];
                                	p_thread_info[n]=p_thread_info[n+1];
                                	p_thread_info[n+1]=aux_thread_info;
                                	sort_ok=1;
                                	}
				}
			}
		}

/*
 * Imprime el array p_thread_info[]
*/

	clock_actual=times(&tms);

	if (VIEW==0)
		{
		printf("\nt_tid   time   t_state       syscall");
		printf("\n----- -------- ------- --------------------------------------");
		cont_l=0;
		for(n=0;n<nthreads;n++)
			{

                	view_ok=0;
                	for(j=0;j<n_lwp;j++)
                        	if (p_thread_info[n].t_tid==list_lwp[j])
                                	view_ok=1;

                	if(n_lwp==0)
                        	view_ok=1;

			syscall_stat[p_thread_info[n].t_sysnum]++;


			if(view_ok)
				{	

        			sprintf(str,"%5.d",p_thread_info[n].t_tid);
				seg=((clock_actual-p_thread_info[n].t_disp_time)/CLK_TCK)%60;
				minx=((clock_actual-p_thread_info[n].t_disp_time)/CLK_TCK)/60;
				min=minx%60;
				hor=minx/60;


				printf("\n%s %0.2d:%0.2d:%0.2d",str,hor,min,seg);

	        		switch(p_thread_info[n].t_state)
					{
		                	case 0:printf(" FREE   ");break;
		                	case 1:printf(" SLEEP  ");break;
		                	case 2:printf(" RUN    ");break;
		                	case 4:printf(" ONPROC ");break;
		                	case 8:printf(" ZOMB   ");break;
		                	case 10:printf(" STOPPED");break;
		                	}
				sprintf(str,"%s(0x%lx, 0x%lx, ...)",syscalltable[p_thread_info[n].t_sysnum],p_thread_info[n].lwp_arg[0],p_thread_info[n].lwp_arg[1]);
				printf(" %-35s",str);

				for(k=0;k<p_thread_info[n].a_nfd;k++)
					{	
					if(p_thread_info[n].a_fd[k]>0)
						{
						for(j=0;j<=nfd_info;j++)
							{
							if(fd_list[j].fd==p_thread_info[n].a_fd[k])
								{
								if (! argv_quick)
									printf("\n\t\t");

									printf(" FD %d:%s",fd_list[j].fd,fd_list[j].text);
								cont_l++;
								}
							}
						}
					}
				if (! argv_all)
					{
					if(NumLines()<(cont_l+10))
						n=nthreads;
					}	
				cont_l++;
				}
			}
		}

	if(VIEW==1)
		{
		printf("\n FD    file info");
		printf("\n----- -----------------------------------------------------");
		cont_l=0;
		for(n=0;n<=nfd_info;n++)
			{
			printf("\n%5d: %s",fd_list[n].fd,fd_list[n].text);
			if (! argv_all)
				if(NumLines()<(cont_l+10))
					n=nfd_info;
			cont_l++;
			}
		cont_l--;
		}

/*
 * Imprime las estadisticas
*/
	if(VIEW==3)
		{
		cont_l=0;
		 for(n=0;n<nthreads;n++)
                        {
                        syscall_stat[p_thread_info[n].t_sysnum]++;
			}

		printf("\n  #  \t syscall");
		printf("\n-----\t ---------------------");
		for(n=0;n<256;n++)
			{
			if( syscall_stat[n]>0)
				{printf("\n%5.d \t %s()",syscall_stat[n], syscalltable[n]);cont_l++;}
			}
		cont_l++;
		}


	printf("\n\n%d <1m, %d <5m, %d <30m, %d <1h, %d <2h, %d >5h\n",nlwp_time[0],nlwp_time[1],nlwp_time[2],nlwp_time[3],nlwp_time[4],nlwp_time[5]);

	if (! argv_all)
		for(n=8+cont_l;n<NumLines();n++)
			printf("\n");

	free(p_thread_info);
	free(fd_list);
	if (argv_all)
		return;
	sleep(nsec);
	}

return;
}



/* 
 * void ErrorParam()
 *
 * Imprime por pantalla los distintos parametros que acepta el programa.
*/

void ErrorParam(char *cad)
	{
	printf("Error: %s\n\n     Usage: lwpfd [-f|-s|-r|-i|-a|-q|-x] [-T seconds] [-t LWPID,LWPID,LWPID,...] -p <pid>",cad);
	printf("\n     Version 0.1.1");
	printf("\n\n         -f show file descriptors.");
	printf("\n\n         -i sort by LWPID.");
	printf("\n         -s sort by systemcall.");
	printf("\n         -r reverse sort.");
	printf("\n         -a show all LWP.");
	printf("\n         -t LWPID LWPID ... show this LWP list.");
	printf("\n         -q Output quick.");
	printf("\n         -x Statistics");
	printf("\n         -p <pid> process ID.");
	printf("\n\n");

	return;
	}


/*
 *  int NumLines()
 *
 *  Devuelve el numero de lineas que tiene el terminal.
*/

int NumLines()
{
struct winsize win_size;
char *env;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win_size) != -1)
       	{
        if (win_size.ws_row > 0)
		return(win_size.ws_row);
	}	

env=getenv("LINES");

if(env)
	return(atoi(env));
}




/*
 * char *inet2char()
 *
 * Convirte una direccion de red en una cadena de texto.
*/

char *inet2char(int addrf, const void *addr, char *str)
{
unsigned char   *p_addr;
p_addr = (char *)addr;

if(addrf == AF_INET)
     	sprintf(str, "%d.%d.%d.%d", (int)p_addr[0], (int)p_addr[1], (int)p_addr[2], (int)p_addr[3]);

if(addrf == AF_INET6)
     	sprintf(str, "<No avalaible>");

return (str);
}


/*
 *
 * Leer la informacion de las lista de descriptores de fichero 
 *
*/

int read_fd_list(kvm_t *kvm_p,proc_t *pproc,struct fd_info **fd_list)
{
uf_entry_t *p_filist;
uf_entry_t ufentry;
file_t ufile;
vnode_t uvnode;
vnode_t uvnode1;
struct sockaddr ufsoa_sa;
struct sockaddr ulsoa_sa;
struct sockaddr_in *so_in;
struct sockaddr_in6 *so_in6;
struct sonode usonode;
inode_t uinode;
struct snode usnode;
struct namenode  unnode;
fifonode_t  ufnode;
struct tmpnode  utnode;
char  abuf[24];
struct vfs uvfsp;
int fstype;
char cadena2[FSTYPSZ];
int cont_fd;
int n;
char c_aux[TXT_SZ_FD];
char c_aux1[TXT_SZ_FD];
char cad[100];
int nfd;
vnode_t *pvnode;
int total_fd;
int SPECIAL_FILE;

nfd=pproc->p_user.u_finfo.fi_nfiles;

total_fd=0;
for(n=0;n<nfd;n++)
       	{
       	p_filist=&pproc->p_user.u_finfo.fi_list[n];

       	if(kvm_read(kvm_p,(uintptr_t)p_filist,&ufentry,sizeof(ufentry))<0)
               	{printf(" Error");}

       	if(ufentry.uf_file>0)
		total_fd++;
	}

*fd_list=(struct fd_info *)malloc(sizeof(struct fd_info)*total_fd);
 if(*fd_list==NULL)
                {printf("\n malloc(): Error no se ha podido reservar memoria \n\n");return(1);}

cont_fd=-1;
for(n=0;n<nfd;n++)
       	{
       	p_filist=&pproc->p_user.u_finfo.fi_list[n];

       	if(kvm_read(kvm_p,(uintptr_t)p_filist,&ufentry,sizeof(ufentry))<0)
               	{printf(" Error p_filist");}

       	if(ufentry.uf_file>0)
               	{
		cont_fd++;
		(*fd_list)[cont_fd].fd=n;
		sprintf((*fd_list)[cont_fd].text,"R[%d]",ufentry.uf_refcnt );

		if(kvm_read(kvm_p,(uintptr_t)ufentry.uf_file,&ufile,sizeof(ufile))<0)
                       	{printf(" Error ufentry.uf_file");}

               	if(kvm_read(kvm_p,(uintptr_t)ufile.f_vnode,&uvnode,sizeof(uvnode))<0)
                       	{printf(" Error ufile.f_vnode");}
		SPECIAL_FILE=0;
               	switch(uvnode.v_type)
                       	{
                        case 0: sprintf(c_aux," %s NON ",(*fd_list)[cont_fd].text);break;
                        case 1: sprintf(c_aux," %s REG ",(*fd_list)[cont_fd].text);break;
                        case 2: sprintf(c_aux," %s DIR ",(*fd_list)[cont_fd].text);break;
                        case 3: sprintf(c_aux," %s BLK ",(*fd_list)[cont_fd].text);break;
                        case 4: sprintf(c_aux," %s CHR ",(*fd_list)[cont_fd].text);SPECIAL_FILE=1;break;
                        case 5: sprintf(c_aux," %s LNK ",(*fd_list)[cont_fd].text);break;
                        case 6: sprintf(c_aux," %s FIFO",(*fd_list)[cont_fd].text);SPECIAL_FILE=2;break;
                        case 7: sprintf(c_aux," %s DOOR",(*fd_list)[cont_fd].text);break;
                        case 8: sprintf(c_aux," %s PROG",(*fd_list)[cont_fd].text);break;
                        case 9: sprintf(c_aux," %s SOCK",(*fd_list)[cont_fd].text);break;
                        case 10: sprintf(c_aux," %s BAD ",(*fd_list)[cont_fd].text);break;
                        }

		sprintf((*fd_list)[cont_fd].text,"%s",c_aux);

                if (uvnode.v_type==9)
                       	{
               		if(kvm_read(kvm_p,(uintptr_t)uvnode.v_data,&usonode,sizeof(usonode))<0)
                       		{printf(" Error uvnode.v_data");}

	                switch(usonode.so_family)
	                        {
	                        case AF_UNSPEC: sprintf(c_aux,"AF_UNSPEC");break;
	                        case AF_UNIX: sprintf(c_aux,"AF_UNIX");break;
	                        case AF_INET: sprintf(c_aux,"AF_INET");break;
	                        case AF_IMPLINK: sprintf(c_aux,"AF_IMPLINK");break;
	                        case AF_INET6: sprintf(c_aux,"AF_INET6");break;
	                        }
			sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
			sprintf((*fd_list)[cont_fd].text,"%s %s",c_aux1,c_aux);

			sprintf(c_aux,"mtime: %l ",usonode.so_mtime);
			sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
			sprintf((*fd_list)[cont_fd].text,"%s %s",c_aux1,c_aux);

               		switch(usonode.so_type)
                       		{
	                        case SOCK_STREAM: sprintf(c_aux,"SOCK_STREAM");break;
	                        case SOCK_DGRAM: sprintf(c_aux,"SOCK_DGRAM");break;
	                        case SOCK_RAW: sprintf(c_aux,"SOCK_RAW");break;
	                        case AF_IMPLINK: sprintf(c_aux,"AF_IMPLINK");break;
	                        case AF_INET6: sprintf(c_aux,"AF_INET6");break;
	                        }

			sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
			sprintf((*fd_list)[cont_fd].text,"%s Type:%s",c_aux1,c_aux);

			if (usonode.so_faddr.soa_len>0)
               			if(kvm_read(kvm_p,(uintptr_t)usonode.so_faddr.soa_sa,&ufsoa_sa,sizeof(ufsoa_sa))<0)
                       			{printf(" Error usonode.so_faddr.soa_sa");}

			if (usonode.so_laddr.soa_len>0)
               			if(kvm_read(kvm_p,(uintptr_t)usonode.so_laddr.soa_sa,&ulsoa_sa,sizeof(ulsoa_sa))<0)
                      			{printf(" Error usonode.so_laddr.soa_sa");}

			if (usonode.so_family == AF_INET)
				{
                               	if (usonode.so_laddr.soa_len>0)
					{
					so_in=(struct sockaddr_in *)&ulsoa_sa;
					sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
					sprintf((*fd_list)[cont_fd].text,"%s L:%s:%d ",c_aux1,  inet2char(usonode.so_family, &so_in->sin_addr, abuf),so_in->sin_port);
					}
					else
					{
					sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
					sprintf((*fd_list)[cont_fd].text,"%s L:0.0.0.0:0 ",c_aux1);
					}

                               	if (usonode.so_faddr.soa_len>0)
					{
					so_in=(struct sockaddr_in *)&ufsoa_sa;
					sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
					sprintf((*fd_list)[cont_fd].text,"%s R:%s:%d ",c_aux1,  inet2char(usonode.so_family, &so_in->sin_addr, abuf),so_in->sin_port);
					}
					else
					{
					sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
					sprintf((*fd_list)[cont_fd].text,"%s R:0.0.0.0:0",c_aux1);
					}
				}
			if (usonode.so_family == AF_INET6)
				{
				so_in6=(struct sockaddr_in6 *)&ulsoa_sa;
				sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
				sprintf((*fd_list)[cont_fd].text,"%s L:%s:%d ",c_aux1,  inet2char(usonode.so_family, &so_in6->sin6_addr, abuf ),so_in6->sin6_port);
				so_in6=(struct sockaddr_in6 *)&ufsoa_sa;
				sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
				sprintf((*fd_list)[cont_fd].text,"%s R:%s:%d ",c_aux1,  inet2char(usonode.so_family, &so_in6->sin6_addr, abuf),so_in6->sin6_port);
				}


               		if (usonode.so_state & SS_ISCONNECTED)
                       		sprintf(c_aux,"CONNECTED");
	                if (usonode.so_state & SS_ISCONNECTING)
	                         sprintf(c_aux,"CONNECTING");
	                if (usonode.so_state & SS_ISDISCONNECTING)
	                         sprintf(c_aux,"ISDISCONNECTING");
	                if (usonode.so_state & SS_CANTSENDMORE)
	                         sprintf(c_aux,"CANTSENDMORE");

	                if (usonode.so_state & SS_ASYNC)
	                         sprintf(c_aux,"ASYNC");

	                if (usonode.so_state & SS_ACCEPTCONN)
	                         sprintf(c_aux,"LISTEN");


			sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
			sprintf((*fd_list)[cont_fd].text,"%s State:%s",c_aux1,c_aux);
			}
			else
			{
               		if(kvm_read(kvm_p,(uintptr_t)uvnode.v_vfsp,&uvfsp,sizeof(uvfsp))<0)
                       		printf(" Error uvnode.v_vfsp");

               		fstype=uvfsp.vfs_fstype;
               		sysfs(GETFSTYP,fstype,cadena2);
			sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
			sprintf((*fd_list)[cont_fd].text,"%s FStype: %s",c_aux1,cadena2);
/*
 * PUNTO DE MONTAJE
*/

               		if (uvfsp.vfs_mntpt)
               			{
               			if(kvm_read(kvm_p,(uintptr_t)uvfsp.vfs_mntpt,&cad,sizeof(cad))<0)
              				{printf(" Error uvfsp.vfs_mntpt");}

				sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
				sprintf((*fd_list)[cont_fd].text,"%s Mount: [ %s ]",c_aux1,cad);
               			}


              		if((strcmp(cadena2,"ufs")==0)&&(SPECIAL_FILE==1))
               			{
               			if(kvm_read(kvm_p,(uintptr_t)uvnode.v_data,&usnode,sizeof(usnode))<0)
                      			{printf(" Error uvnode.v_data %d",cont_fd);}
					else
					{
               				if(kvm_read(kvm_p,(uintptr_t)usnode.s_realvp,&uvnode1,sizeof(uvnode1))<0)
                      				{printf(" Error usnode.s_realvp1 %d",cont_fd);}
						else
						{
               					if(kvm_read(kvm_p,(uintptr_t)uvnode1.v_data,&uinode,sizeof(uinode))<0)
                      					{printf(" Error uvnode1.v_data");}

							sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
							sprintf((*fd_list)[cont_fd].text,"%s inode: %lllu",c_aux1,uinode.i_number);
						}
					}
               			}


              		if((strcmp(cadena2,"ufs")==0)&&(SPECIAL_FILE==0))
               			{
               			if(kvm_read(kvm_p,(uintptr_t)uvnode.v_data,&uinode,sizeof(uinode))<0)
                      			{printf(" Error uvnode.v_data");}
				sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
				sprintf((*fd_list)[cont_fd].text,"%s inode: %lllu",c_aux1,uinode.i_number);
               			}

              		if(strcmp(cadena2,"fifofs")==0)
              			{
               			if(kvm_read(kvm_p,(uintptr_t)uvnode.v_data,&ufnode,sizeof(ufnode))<0)
                       			{printf(" Error");}

				sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
				sprintf((*fd_list)[cont_fd].text,"%s inode: %lllu",c_aux1,ufnode.fn_ino);

               			}

              		if(strcmp(cadena2,"tmpfs")==0)
               			{
               			if(kvm_read(kvm_p,(uintptr_t)uvnode.v_data,&utnode,sizeof(utnode))<0)
                       			{printf(" Error");}
				sprintf(c_aux1,"%s",(*fd_list)[cont_fd].text);
				sprintf((*fd_list)[cont_fd].text,"%s inode: %lllu",c_aux1,utnode.tn_attr.va_nodeid);
               			}
			}
               	}
	}
return(cont_fd);
}






/*
 *
 * Leer la informacion de los threads
 *
*/


void read_thread_info(kvm_t *kvm_p,proc_t *pproc,int nthreads,struct thread_info *p_thread_info,int *nlwp_time)
{
int n;
int minx;
kthread_t pkthr_list;
klwp_t pklwp;
struct tms tms;
ulong clock_actual;


        if(kvm_read(kvm_p,(uintptr_t)pproc->p_tlist,&pkthr_list,sizeof(pkthr_list))<0)
                {printf("\nkvm_read: Error leyendo p_tlist");}
        clock_actual=times(&tms);

        for(n=0;n<6;n++)
                nlwp_time[n]=0;

        for(n=0;n<nthreads;n++)
                {
                p_thread_info[n].t_tid=pkthr_list.t_tid;
                p_thread_info[n].t_disp_time=pkthr_list.t_disp_time;

                minx=((clock_actual-p_thread_info[n].t_disp_time)/CLK_TCK)/60;

                if(minx<1)
                        nlwp_time[0]++;
                if((minx>=1)&&(minx<5))
                        nlwp_time[1]++;
                if((minx>=5)&&(minx<30))
                        nlwp_time[2]++;
                if((minx>=30)&&(minx<60))
                        nlwp_time[3]++;
                if((minx>=60)&&(minx<300))
                        nlwp_time[4]++;
                if(minx>=300)
                        nlwp_time[5]++;

                p_thread_info[n].t_state=pkthr_list.t_state;

                p_thread_info[n].a_nfd=pkthr_list.t_activefd.a_nfd;


                if(kvm_read(kvm_p,(uintptr_t)pkthr_list.t_activefd.a_fd,&p_thread_info[n].a_fd,sizeof(int)*pkthr_list.t_activefd.a_nfd)<0)
                        {printf("\nkvm_read: Error leyendo t_activefd");}


                if(kvm_read(kvm_p,(uintptr_t)pkthr_list.t_lwp,&pklwp,sizeof(pklwp))<0)
                        {printf("\nkvm_read: Error leyendo t_lwp");}

                p_thread_info[n].t_sysnum=pkthr_list.t_sysnum;
                p_thread_info[n].lwp_arg[0]=pklwp.lwp_arg[0];
                p_thread_info[n].lwp_arg[1]=pklwp.lwp_arg[1];




                if(kvm_read(kvm_p,(uintptr_t)pkthr_list.t_forw,&pkthr_list,sizeof(pkthr_list))<0)
                        {printf("\nkvm_read: Error leyendo t_forw");}
        	}

return;
}

